From 1d9fff9e9224d2b2d2589e05b115f109a030cb31 Mon Sep 17 00:00:00 2001 From: "Evgeny Grechnikov (Diamond)" Date: Thu, 26 Jul 2007 12:45:49 +0000 Subject: [PATCH] KFar 0.4 + KFar_Arc 0.1 git-svn-id: svn://kolibrios.org@589 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/fs/kfar/trunk/api.txt | 137 + programs/fs/kfar/trunk/dialogs.inc | 99 +- programs/fs/kfar/trunk/filetool.inc | 653 +++- programs/fs/kfar/trunk/kfar.asm | 1144 ++++++- programs/fs/kfar/trunk/kfar.ini | 43 + programs/fs/kfar/trunk/kfar_arc/7z.inc | 3138 ++++++++++++++++++ programs/fs/kfar/trunk/kfar_arc/7zaes.inc | 216 ++ programs/fs/kfar/trunk/kfar_arc/7zbranch.inc | 469 +++ programs/fs/kfar/trunk/kfar_arc/aes.inc | 274 ++ programs/fs/kfar/trunk/kfar_arc/crc.inc | 32 + programs/fs/kfar/trunk/kfar_arc/kfar_arc.asm | 1075 ++++++ programs/fs/kfar/trunk/kfar_arc/kglobals.inc | 50 + programs/fs/kfar/trunk/kfar_arc/lang.inc | 1 + programs/fs/kfar/trunk/kfar_arc/lzma.inc | 581 ++++ programs/fs/kfar/trunk/kfar_arc/ppmd.inc | 1485 +++++++++ programs/fs/kfar/trunk/kfar_arc/sha256.inc | 238 ++ programs/fs/kfar/trunk/tools.inc | 96 +- programs/fs/kfar/trunk/viewer.inc | 204 +- 18 files changed, 9730 insertions(+), 205 deletions(-) create mode 100644 programs/fs/kfar/trunk/api.txt create mode 100644 programs/fs/kfar/trunk/kfar.ini create mode 100644 programs/fs/kfar/trunk/kfar_arc/7z.inc create mode 100644 programs/fs/kfar/trunk/kfar_arc/7zaes.inc create mode 100644 programs/fs/kfar/trunk/kfar_arc/7zbranch.inc create mode 100644 programs/fs/kfar/trunk/kfar_arc/aes.inc create mode 100644 programs/fs/kfar/trunk/kfar_arc/crc.inc create mode 100644 programs/fs/kfar/trunk/kfar_arc/kfar_arc.asm create mode 100644 programs/fs/kfar/trunk/kfar_arc/kglobals.inc create mode 100644 programs/fs/kfar/trunk/kfar_arc/lang.inc create mode 100644 programs/fs/kfar/trunk/kfar_arc/lzma.inc create mode 100644 programs/fs/kfar/trunk/kfar_arc/ppmd.inc create mode 100644 programs/fs/kfar/trunk/kfar_arc/sha256.inc diff --git a/programs/fs/kfar/trunk/api.txt b/programs/fs/kfar/trunk/api.txt new file mode 100644 index 0000000000..164ce258aa --- /dev/null +++ b/programs/fs/kfar/trunk/api.txt @@ -0,0 +1,137 @@ +Плагин представляет собой стандартную для Колибри динамическую библиотеку (формата COFF), +экспортирующую следующие функции и переменные (некоторые функции могут отсутствовать). +Функции могут разрушать любые регистры. kfar гарантирует сброшенный флаг направления DF +при вызове экспортируемых функций и ожидает того же для callback-функций. + +int version; +Версия интерфейса kfar, на которую рассчитан плагин. Сейчас должна быть 1. + +int __stdcall plugin_load(kfar_info* info); +Вызывается при загрузке плагина. +typedef struct +{ + int StructSize; // = sizeof(kfar_info) + int kfar_ver; // 10000h*major + minor +/* Все callback-функции сохраняют все регистры, за исключением eax. */ +/* Функции работы с файлами: */ + void* open; // HANDLE __stdcall open(const char* name, int mode); + // mode - комбинация битовых флагов + // O_READ = 1 - доступ для чтения + // O_WRITE = 2 - доступ для записи + // O_CREATE = 4 - если файл не существует, создать его + // O_TRUNCATE = 8 - усечь файл до нулевой длины + void* read; // unsigned __stdcall read(HANDLE hFile, void* buf, unsigned size); + void* write; // ещё не реализовано + void* seek; // void __stdcall seek(HANDLE hFile, int method, __int64 newpos); + void* flush; // ещё не реализовано + void* filesize; // __int64 __stdcall filesize(HANDLE hFile); + void* close; // void __stdcall close(HANDLE hFile); +/* Функции работы с памятью (постранично): */ + void* pgalloc; // in: ecx=size, out: eax=pointer or NULL + // при нехватке памяти сообщает пользователю и возвращает NULL + void* pgrealloc; // in: edx=pointer, ecx=new size, out: eax=pointer or NULL + // при нехватке памяти сообщает пользователю и возвращает NULL + void* pgfree; // in: ecx=pointer + void* getfreemem; // unsigned __stdcall getfreemem(void); + // возвращает размер свободной оперативной памяти в Кб + void* pgalloc2; // void* __stdcall pgalloc2(unsigned size); + void* pgrealloc2; // void* __stdcall pgrealloc2(void* pointer, unsigned size); + void* pgfree2; // void __stdcall pgfree2(void* pointer); +/* Функции работы с диалогами: */ + void* menu; // int __stdcall menu(void* variants, const char* title, unsigned flags); + // variants указывает на текущий элемент в двусвязном списке + void* menu_centered_in; // int __stdcall menu_centered_in(unsigned left, unsigned top, + // unsigned width, unsigned height, + // void* variants, const char* title, unsigned flags); + void* DialogBox; // int __stdcall DialogBox(DLGDATA* dlg); + void* SayErr; // int __stdcall SayErr(int num_strings, const char** strings, + // int num_buttons, const char** buttons); + void* Message; // int __stdcall Message(const char* title, + // int num_strings, const char** strings, + // int num_buttons, const char** buttons); + // may be x=-1 and/or y=-1 + struct {unsigned width;unsigned height;}* cur_console_size; +} kfar_info; +Возвращаемое значение: +0 = успешная инициализация +1 = ошибка инициализации (kfar выдаст сообщение пользователю) +2 = ошибка инициализации (kfar продолжит без сообщений) + +void __stdcall plugin_unload(void); +Вызывается при выгрузке плагина (в процессе завершения работы kfar). + +HANDLE __stdcall OpenFilePlugin(HANDLE basefile, const char* name, + const void* attr, const void* data, int datasize); +Открывает плагин, эмулирующий файловую систему на базе файла (например, архива). +basefile - хэндл файла (к которому применимы функции read и seek из kfar_info) +name - имя файла (во временном буфере) +attr - указатель на структуру с атрибутами файла в формате системной функции 70.1 +data - буфер, содержащий данные из начала файла (может использоваться для определения типа файла) +datasize - размер данных в data. В текущей реализации min(1024,размер файла) +Если плагин обрабатывает переданный файл, то он должен вернуть новый описатель, +который в дальнейшем будет использовать kfar для обращения к плагину. В этом случае +плагин должен самостоятельно закрыть basefile функцией close из kfar_info (например, +при закрытии описателя плагина в ClosePlugin или непосредственно в OpenFilePlugin, +если basefile вообще впоследствии не нужен). +Если плагин не обрабатывает переданный файл, должен возвращаться 0. +Если операция прервана пользователем, должно возвращаться значение -1. + +void __stdcall ClosePlugin(HANDLE hPlugin); +Закрывает созданный в OpenFilePlugin описатель. + +void __stdcall GetOpenPluginInfo(HANDLE hPlugin, OpenPluginInfo* Info); +Получить информацию об открытом экземпляре плагина. +typedef struct +{ + unsigned flags; // бит 0: добавлять элемент '..', если он отсутствует + // бит 1: копирование обрабатывается функцией GetFiles +} OpenPluginInfo; + +void __stdcall GetPanelTitle(HANDLE hPlugin, char title[1024], + const char* host_file, const char* curdir); +Получить заголовок панели плагина. Параметр host_file совпадает с именем файла, переданным +в OpenFilePlugin. Параметр curdir совпадает с текущей папкой, устанавливаемой в SetFolder. + +int __stdcall ReadFolder(HANDLE hPlugin, unsigned dirinfo_start, + unsigned dirinfo_size, void* dirdata); +Читает текущую папку. hPlugin - возвращённый из OpenFilePlugin описатель. +dirinfo_start - с какого файла читать, dirinfo_size - сколько файлов читать. +Возвращаемое значение и возвращаемые в dirdata данные должны соответствовать функции 70.1. + +bool __stdcall SetFolder(HANDLE hPlugin, const char* relative_path, const char* absolute_path); +Установить текущую папку. relative_path - относительный путь (".." или имя подпапки), +absolute_path - абсолютный путь (папка эмулируемой плагином файловой системы). + +void __stdcall GetFiles(HANDLE hPlugin, int NumItems, void* items[], void* addfile, void* adddir); + bool __stdcall addfile(const char* name, void* bdfe_info, HANDLE hFile); + bool __stdcall adddir(const char* name, void* bdfe_info); +Вызывается для копирования, если во флагах, возвращаемых GetOpenPluginInfo, установлен бит 1. +Эту функцию рекомендуется реализовывать в случае, если стандартный рекурсивный обход папок +неудобен. +hPlugin - описатель, созданный в OpenFilePlugin. +NumItems - число копируемых элементов. +items - массив копируемых элементов, каждый из которых задаётся указателем на структуру BDFE. +Специальный случай NumItems=-1, items=NULL означает "все файлы" (в текущей папке и подпапках). +addfile, adddir - callback-функции kfar'а. Возврат false означает "прервать копирование". +Параметр name должен задавать имя относительно текущей папки. Параметр bdfe_info - +указатель на сокращённую (40 байт) запись в формате функции 70.5. +Открытием и закрытием описателя hFile должен заниматься плагин. Функция addfile будет +вызывать только функцию read. + +int __stdcall getattr(HANDLE hPlugin, const char* filename, void* info); +Получить информацию о файле. Возвращаемое значение и данные в info должны соответствовать +функции 70.5. + +HANDLE __stdcall open(HANDLE hPlugin, const char* filename, int mode); +Открыть файл filename. Параметр mode зарезервирован и в текущей версии kfar всегда равен 1. + +unsigned __stdcall read(HANDLE hFile, void* buf, unsigned size); +Чтение size байт в буфер buf из файла hFile, ранее открытого через open. +kfar гарантирует, что size кратен 512 байт. +Возвращаемое значение: число прочитанных байт, -1 при ошибке. + +void __stdcall setpos(HANDLE hFile, __int64 pos); +Установить текущую позицию в файле hFile, ранее открытого через open, в pos. +Гарантируется, что pos кратно 512 байт. + +void __stdcall close(HANDLE hFile); diff --git a/programs/fs/kfar/trunk/dialogs.inc b/programs/fs/kfar/trunk/dialogs.inc index 553bce0b8e..779794b366 100644 --- a/programs/fs/kfar/trunk/dialogs.inc +++ b/programs/fs/kfar/trunk/dialogs.inc @@ -320,8 +320,7 @@ GenericBox: jz .redraw dec eax jz .key - or eax, -1 - int 40h + jmp exit .redraw: push ebx ebp call draw_window @@ -772,6 +771,10 @@ MenuDlgProc: jz .pgdn cmp al, 0x49 jz .pgup + cmp al, 0x52 + jz .ins + cmp al, 0x53 + jz .del mov edx, [ebx+36] @@: cmp dword [edx+4], 0 @@ -858,6 +861,28 @@ MenuDlgProc: .enter: mov eax, [ebx+36] ret 16 +.ins: + push 5 + pop edx + jmp @f +.del: + push 4 + pop edx +@@: + mov eax, [ebx+36] + cmp byte [eax+8], '/' + jnz @f + cmp word [eax+9], 'cd' + jnz @f + movzx ecx, byte [eax+11] + sub ecx, '0' + push 24 + pop eax + mov ebx, edx + int 40h +@@: + xor eax, eax + ret 16 .line_prev: cmp eax, [ebx+44] @@ -1016,6 +1041,7 @@ dlgitemtemplate: ; 8 = элемент может иметь фокус ввода ; 10h: для кнопки = кнопка по умолчанию (Enter на не-кнопке) ; для поля ввода = данные были модифицированы +; 20h: для поля ввода = не отображать вводимые данные (показывать '*') .size = $ end virtual ; struct DLGDATA @@ -1309,7 +1335,8 @@ draw_text: draw_text_esi: test esi, esi jz .ret - or ecx, -1 + push -1 + pop ecx @@: inc ecx cmp byte [ecx+esi], 0 @@ -1372,6 +1399,14 @@ draw_text_esi: sub esi, ecx .text_copy: jecxz .ret +; check for password editboxes + cmp [ebx+dlgitemtemplate.type], 3 + jnz @f + test [ebx+dlgitemtemplate.flags], 20h + jz @f + mov al, '*' + rep stosw + jmp .ret @@: lodsb stosw @@ -1441,31 +1476,30 @@ SayNoMem: call DialogBox ret -; int __stdcall SayErr(const char* title, int x, int y, -; int num_strings, const char* strings[], -; int num_buttons, const char* buttons[]); -; may be x=-1 and/or y=-1 +; int __stdcall SayErr(int num_strings, const char* strings[], +; int num_buttons, const char* buttons[]); SayErr: + pop eax + push aError + push eax push 2 jmp @f -; int __stdcall Message(const char* title, int x, int y, +; int __stdcall Message(const char* title, ; int num_strings, const char* strings[], ; int num_buttons, const char* buttons[]); Message: push 1 @@: -; [esp+4] = title -; [esp+8] = x -; [esp+12] = y -; [esp+16] = num_strings -; [esp+20] = strings -; [esp+24] = num_buttons -; [esp+28] = buttons pop eax +; [esp+4] = title +; [esp+8] = num_strings +; [esp+12] = strings +; [esp+16] = num_buttons +; [esp+20] = buttons pushad - mov ecx, [esp+4+16] - add ecx, [esp+4+24] + mov ecx, [esp+32+8] + add ecx, [esp+32+16] imul ecx, dlgitemtemplate.size add ecx, dlgtemplate.size+12 call xpgalloc @@ -1479,13 +1513,12 @@ Message: mov edi, eax mov eax, [esp+28] stosd ; dlgtemplate.flags - mov eax, [esp+32+8] + or eax, -1 stosd ; dlgtemplate.x - mov eax, [esp+32+12] stosd ; dlgtemplate.y ; calculate width - mov ecx, [esp+32+16] - mov esi, [esp+32+20] + mov ecx, [esp+32+8] + mov esi, [esp+32+12] xor edx, edx .calcwidth: lodsd @@ -1500,8 +1533,8 @@ Message: mov edx, eax @@: loop .calcwidth - mov ecx, [esp+32+24] - mov esi, [esp+32+28] + mov ecx, [esp+32+16] + mov esi, [esp+32+20] xor ebp, ebp .calcwidth2: lodsd @@ -1527,7 +1560,7 @@ Message: @@: mov eax, edx stosd ; dlgtemplate.width - mov eax, [esp+32+16] + mov eax, [esp+32+8] inc eax stosd ; dlgtemplate.height mov eax, 3 @@ -1540,12 +1573,12 @@ Message: stosd ; (ignored) stosd ; DlgProc stosd ; userdata - mov eax, [esp+32+16] - add eax, [esp+32+24] + mov eax, [esp+32+8] + add eax, [esp+32+16] stosd ; num_items ; fill strings xor ecx, ecx - mov esi, [esp+32+20] + mov esi, [esp+32+12] @@: mov eax, 1 stosd ; dlgitemtemplate.type @@ -1561,11 +1594,11 @@ Message: mov eax, 1 stosd ; dlgitemtemplate.flags inc ecx - cmp ecx, [esp+32+16] + cmp ecx, [esp+32+8] jb @b ; fill buttons - mov ecx, [esp+32+24] - mov esi, [esp+32+28] + mov ecx, [esp+32+16] + mov esi, [esp+32+20] sub edx, ebp jc .big shr edx, 1 @@ -1596,7 +1629,7 @@ Message: mov eax, [esi-4] stosd ; dlgitemtemplate.data mov eax, 9 - cmp ecx, [esp+32+24] + cmp ecx, [esp+32+16] jnz @f or al, 4 @@: @@ -1611,10 +1644,10 @@ Message: xor edx, edx mov ecx, dlgitemtemplate.size div ecx - sub eax, [esp+32+16] + sub eax, [esp+32+8] @@: mov [esp+28], eax mov ecx, ebx call pgfree popad - ret 28 + ret 20 diff --git a/programs/fs/kfar/trunk/filetool.inc b/programs/fs/kfar/trunk/filetool.inc index 4e63c38028..ca7991109f 100644 --- a/programs/fs/kfar/trunk/filetool.inc +++ b/programs/fs/kfar/trunk/filetool.inc @@ -29,9 +29,6 @@ delete_file_worker: push 4 push eax push 3 - push -1 - push -1 - push aError call SayErr add esp, 3*4 cmp al, -1 @@ -66,6 +63,8 @@ delete_file: mov esi, [esp+28] mov ecx, esi add esi, 40 + cmp byte [edi-1], '/' + jz .l1 mov al, '/' stosb .l1: @@ -239,9 +238,6 @@ makedir: push dword [eax+16] push eax push 3 - push -1 - push -1 - push dword aError call SayErr add esp, 3*4 test eax, eax @@ -253,6 +249,9 @@ copy_file_worker: ; in: execdata = source name, CopyDestEditBuf+12 = destination name, edx = BDFE block for source ; out: CF and ZF not set <=> cancel job ("ja cancel_label") ; destroys eax,esi,edi + lea edi, [edx+40] + and [source_hFile], 0 +copy_file_worker2: push CopyDestEditBuf+12+513 cmp [bDestIsFolder], 0 jz .noaddtoname @@ -261,11 +260,15 @@ copy_file_worker: lodsb test al, al jnz @b - mov byte [esi-1], '/' - pop edi + pop eax + dec esi push esi - mov edi, esi - lea esi, [edx+40] + cmp byte [esi-1], '/' + jz @f + mov byte [esi], '/' + inc esi +@@: + xchg esi, edi @@: cmp edi, CopyDestEditBuf+12+513 jae .overflow @@ -277,12 +280,14 @@ copy_file_worker: .overflow: .ret_zf: pop esi - and byte [esi-1], 0 ; ZF=1 + and byte [esi], 0 ; ZF=1 ret .noaddtoname: -; ═хы№ч  ёъюяшЁютрЄ№ Їрщы яютхЁї ёрьюую ёхс ! +; Нельзя скопировать файл поверх самого себя! mov esi, execdata mov edi, CopyDestEditBuf+12 + cmp [source_hModule], 0 + jnz @f push esi edi call strcmpi pop edi esi @@ -294,15 +299,12 @@ copy_file_worker: push 1 push eax push 2 - push -1 - push -1 - push aError call SayErr pop eax pop eax jmp .ret_zf @@: -; ╤юсёЄтхээю, ъюяшЁєхь +; Собственно, копируем ; esi->source name, edi->destination name push ebx mov [writeinfo.code], 2 @@ -316,8 +318,40 @@ copy_file_worker: mov [ebx+readinfo.size-readinfo], copy_buffer_size mov [ebx+readinfo.data-readinfo], copy_buffer mov [ebx+readinfo.name-readinfo], esi + mov eax, [source_hFile] + push eax + test eax, eax + jnz .copyloop +.source_reopen: + mov eax, [source_hModule] + test eax, eax + jz .copyloop + pushad + push O_READ+O_SEQUENTIAL_ONLY + push esi + push [source_hPlugin] + call [eax+PluginInfo.open] + mov [source_hFile], eax + popad .copyloop: mov ebx, readinfo + mov eax, [source_hModule] + test eax, eax + jz .native + mov ecx, [source_hFile] + jecxz .readerr + pushad + push [ebx+readinfo.size-readinfo] + push [ebx+readinfo.data-readinfo] + push ecx + call [eax+PluginInfo.read] + mov [esp+28], eax + popad + cmp eax, -1 + jz .readerr + mov ebx, eax + jmp .copyreadok +.native: push 70 pop eax int 0x40 @@ -325,6 +359,7 @@ copy_file_worker: jz .copyreadok cmp eax, 6 jz .copyreadok +.readerr: cmp [copy_bSkipAll2], 0 jnz .copyfailed_del2 push esi @@ -336,14 +371,15 @@ copy_file_worker: push 4 push eax push 3 - push -1 - push -1 - push dword aError call SayErr add esp, 3*4 test eax, eax + jnz .copyfailed_parseuser + cmp [source_hModule], 0 jz .copyloop - jmp .copyfailed_parseuser + cmp [source_hFile], 0 + jz .source_reopen + jmp .copyloop .copyreadok: add dword [readinfo.first], ebx adc dword [readinfo.first+4], 0 @@ -370,9 +406,6 @@ copy_file_worker: push 4 push eax push 3 - push -1 - push -1 - push dword aError call SayErr add esp, 3*4 test eax, eax @@ -394,12 +427,48 @@ copy_file_worker: cmp ecx, copy_buffer_size jz .copyloop .copydone: + pop ecx + test ecx, ecx + jnz @f + mov eax, [source_hModule] + test eax, eax + jz @f + mov ecx, [source_hFile] + jecxz @f + push edx + push ecx + call [eax+PluginInfo.close] + pop edx +@@: ; now try to set attributes from source, ignore errors mov edi, attrinfo.attr mov esi, edx push 8 pop ecx rep movsd +; replace zero dates with default values + mov eax, [default_attr] + cmp dword [edi-32+8], 0 + jnz @f + mov ecx, [eax+8] + mov [edi-32+8], ecx + mov ecx, [eax+12] + mov [edi-32+12], ecx +@@: + cmp dword [edi-32+16], 0 + jnz @f + mov ecx, [eax+16] + mov [edi-32+16], ecx + mov ecx, [eax+20] + mov [edi-32+20], ecx +@@: + cmp dword [edi-32+24], 0 + jnz @f + mov ecx, [eax+24] + mov [edi-32+24], ecx + mov ecx, [eax+28] + mov [edi-32+28], ecx +@@: mov ebx, attrinfo mov [ebx+attrinfo.name-attrinfo], CopyDestEditBuf+12 inc dword [ebx] @@ -413,12 +482,23 @@ copy_file_worker: .ret: pop ebx pop esi - mov byte [esi-1], 0 + mov byte [esi], 0 ret .copydone2: popf jmp .ret .copyfailed: + pop ecx + test ecx, ecx + jnz @f + mov eax, [source_hModule] + test eax, eax + jz @f + mov ecx, [source_hFile] + jecxz @f + push ecx + call [eax+PluginInfo.close] +@@: cmp [bConfirmDeleteIncomplete], 0 jz .copyfailed_del cmp [writeinfo.code], 2 @@ -429,10 +509,8 @@ copy_file_worker: push 2 push eax push 1 - push -1 - push -1 push dword aCopyCaption - call SayErr + call Message add esp, 4 test eax, eax jnz .copydone2 @@ -468,6 +546,8 @@ copy_file: @@: mov esi, [esp+28] add esi, 40 + cmp byte [edi-1], '/' + jz .l1 mov al, '/' stosb .l1: @@ -475,6 +555,7 @@ copy_file: cmp edi, execdataend jb @f call panels_OnKey.bigfilename + stc popad ret @@: @@ -504,7 +585,12 @@ copy_file: lodsb test al, al jnz @b - mov byte [esi-1], '/' + dec esi + cmp byte [esi-1], '/' + jz @f + mov byte [esi], '/' + inc esi +@@: mov edi, esi lea esi, [edx+40] @@: @@ -527,8 +613,44 @@ copy_file: @@: cmp al, 1 jz .copy_dir_entry_done - jmp .cancel + jmp .cancel2 .target_created: + mov edx, [source_hModule] + test edx, edx + jz .nosetdir + mov esi, execdata + push esi ; absolute_path +@@: + lodsb + test al, al + jnz @b +@@: + dec esi + cmp byte [esi-1], '/' + jnz @b + push esi ; relative_path + push [source_hPlugin] ; hPlugin + call [edx+PluginInfo.SetFolder] + test al, al + jnz .nosetdir + cmp [copy_bSkipAll3], 0 + jz .skip2 + push execdata + push aCannotSetFolder + mov eax, esp + push DeleteErrorBtn + push 4 + push eax + push 2 + call SayErr + pop ecx ecx + test al, al + jz .target_created + cmp al, 2 + setz [copy_bSkipAll3] + ja .cancel2 + jmp .skip2 +.nosetdir: xor ebp, ebp ; ebp will contain number of copied items .return_from_recursion: .read_retry: @@ -537,16 +659,30 @@ copy_file: mov [ebx+dirinfo.size-dirinfo], copy_dir_query_size mov [ebx+dirinfo.dirdata-dirinfo], copy_dir_query_area mov [ebx+dirinfo.name-dirinfo], execdata + mov eax, [source_hModule] + test eax, eax + jz .readfolder_native + push ebp + push [ebx+dirinfo.dirdata-dirinfo] + push [ebx+dirinfo.size-dirinfo] + push [ebx+dirinfo.first-dirinfo] + push [source_hPlugin] + call [eax+PluginInfo.ReadFolder] + pop ebp + mov ebx, dword [copy_dir_query_area+4] + jmp @f +.readfolder_native: push 70 pop eax int 0x40 +@@: test eax, eax jz .readok cmp eax, 6 jz .readok ; read error cmp [copy_bSkipAll], 0 - jz .skip1 + jnz .skip1 push execdata push aCannotReadFolder call get_error_msg @@ -556,9 +692,6 @@ copy_file: push 4 push eax push 3 - push -1 - push -1 - push aError call SayErr add esp, 3*4 test al, al @@ -597,7 +730,12 @@ copy_file: lodsb test al, al jnz @b - mov byte [esi-1], '/' + dec esi + cmp byte [esi-1], '/' + jz @f + mov byte [esi], '/' + inc esi +@@: mov edi, esi lea esi, [edx+40] @@: @@ -612,7 +750,12 @@ copy_file: lodsb test al, al jnz @b - mov byte [esi-1], '/' + dec esi + cmp byte [esi-1], '/' + jz @f + mov byte [esi], '/' + inc esi +@@: mov edi, esi lea esi, [edx+40] @@: @@ -625,7 +768,7 @@ copy_file: test byte [edx], 10h jnz .entry_is_folder call copy_file_worker - ja .cancel + ja .cancel3 jmp .restore_name .entry_is_folder: ; allocate new item in directory stack @@ -642,7 +785,6 @@ copy_file: .fullname2_big: mov esi, CopyDestEditBuf+12+512 jmp .restore_name2 -.skip1: .restore_name: mov esi, CopyDestEditBuf+12 @@: @@ -665,8 +807,23 @@ copy_file: .copy_dir_entry_continue: add edx, 304 jmp .copy_dir_entry_loop +.skip1: .copy_dir_entry_done: ; return to previous directory + mov esi, execdata + call delete_last_name_from_end + mov eax, [source_hModule] + test eax, eax + jz @f + push execdata + push aDotDot + push [source_hPlugin] + call [eax+PluginInfo.SetFolder] + jmp @f +.skip2: + mov esi, execdata + call delete_last_name_from_end +@@: ; pop item from directory stack mov ecx, [copy_dir_stack_ptr] cmp ecx, copy_dir_stack @@ -675,16 +832,34 @@ copy_file: mov [copy_dir_stack_ptr], ecx mov ebp, [ecx] ; restore prev directory name - mov esi, execdata - call delete_last_name_from_end mov esi, CopyDestEditBuf+12 call delete_last_name_from_end jmp .return_from_recursion .done: -.cancel: mov [dirinfo.first], 0 ; do not destroys flags popad ret +.cancel2: + sub [copy_dir_stack_ptr], 4 +.cancel3: + mov esi, execdata + call delete_last_name_from_end +.cancel: + mov eax, [source_hModule] + test eax, eax + jz .cancel.ret + cmp [copy_dir_stack_ptr], copy_dir_stack + jb .cancel.ret + push execdata + push aDotDot + push [source_hPlugin] + call [eax+PluginInfo.SetFolder] + jmp .cancel2 +.cancel.ret: + xor eax, eax + inc eax + popad + ret delete_last_name_from_end: lodsb @@ -699,5 +874,403 @@ delete_last_name: cmp al, '/' jnz @b cld + inc esi + cmp esi, execdata + jz @f + cmp esi, CopyDestEditBuf+12 + jz @f + dec esi +@@: mov byte [esi+1], 0 ret + +copy_AddDir: + push 1 + pop eax ; for "return true" + pushad + mov esi, CopyDestEditBuf+12 +@@: + lodsb + test al, al + jnz @b + cmp byte [esi-2], '/' + jnz @f + dec esi +@@: + push dword [esi-1] + push esi + mov byte [esi-1], '/' + mov edi, esi + mov esi, [esp+28h+4] +.0: + lodsb + stosb + cmp edi, CopyDestEditBuf+12+512 + jae .done + test al, al + jnz .0 + push RetryOrCancelBtn + push 2 + call makedir + jz .done + and dword [esp+8+1Ch], 0 +.done: + pop esi + pop dword [esi-1] + popad + ret 8 + +copy_AddFile: + pushad + mov eax, [esp+20h+12] + mov [source_hFile], eax + mov edx, [esp+20h+8] + mov edi, [esp+20h+4] + call copy_file_worker2 + popad + setna al + ret 12 + +virtual at 0 +_FILE: +.pos dq ? +.bufpos dq ? +.bufsize dd ? +.mode dd ? +.hPlugin dd ? +.hFile dd ? +.fileinfo: +.fimode dd ? +.fioffset dq ? +.fisize dd ? +.fibuf dd ? +.finame rb 1024 +.attr rb 40 +align 512 +.buf rb 2048 +.size = $ +end virtual + +O_READ = 1 ; allows read from file +O_WRITE = 2 ; allows write to file +O_CREATE = 4 ; if file does not exist and this flag is set, create file; + ; if file does not exist and this flag is not set, fail +O_TRUNCATE = 8 ; truncate file if it exists +O_SEQUENTIAL_ONLY = 10h ; there will be no 'seek'/'setpos' calls + +; HANDLE __stdcall open(const char* name, int mode); +; Opens physical file +open: + pushad + mov ecx, _FILE.size + call xpgalloc + test eax, eax + jz .ret0z + mov [esp+28], eax + mov ecx, eax + mov esi, [esp+36] + lea edi, [eax+_FILE.finame] + lea edx, [eax+_FILE.finame+1024] +@@: + lodsb + stosb + test al, al + jz @f + cmp edi, edx + jb @b +.ret0: + call pgfree +.ret0z: + popad + xor eax, eax + ret 8 +@@: + mov eax, [esp+40] + mov [ecx+_FILE.mode], eax +.getattr: + lea edi, [ecx+_FILE.fileinfo] + mov ebx, edi + push 5 + pop eax + stosd + xor eax, eax + stosd + stosd + stosd + lea eax, [ecx+_FILE.attr] + stosd + push 70 + pop eax + int 0x40 + test eax, eax + jz .found + cmp eax, 5 + jnz .ret0 +; file does not exist + test [ecx+_FILE.mode], O_CREATE + jz .ret0z +.truncate: + lea ebx, [ecx+_FILE.fileinfo] + mov byte [ebx], 2 + push 70 + pop eax + int 0x40 + test eax, eax + jz .getattr + jmp .ret0 +.found: + test [ecx+_FILE.mode], O_TRUNCATE + jz @f + cmp dword [ecx+_FILE.attr+36], eax + jnz .truncate + cmp dword [ecx+_FILE.attr+32], eax + jnz .truncate +@@: + mov dword [ecx+_FILE.pos], eax + mov dword [ecx+_FILE.pos+4], eax + mov dword [ecx+_FILE.bufpos], eax + mov dword [ecx+_FILE.bufpos+4], eax + mov [ecx+_FILE.bufsize], eax + mov [ecx+_FILE.hPlugin], eax + mov [ecx+_FILE.hFile], eax + mov dword [ecx+_FILE.fioffset], eax + mov dword [ecx+_FILE.fioffset+4], eax + mov [esp+28], ecx + popad + ret 8 + +; unsigned __stdcall read(HANDLE hFile, void* buf, unsigned size); +read: + xor eax, eax + pushad + mov ecx, [esp+36] + test [ecx+_FILE.mode], O_READ + jnz @f +.ret: + popad + ret 12 +@@: + cmp dword [esp+44], eax + jz .ret + mov [ecx+_FILE.fimode], eax + mov ebx, [ecx+_FILE.bufsize] + mov eax, dword [ecx+_FILE.pos] + and eax, 2047 + sub ebx, eax + jbe .nobuf0 + cmp ebx, [esp+44] + jbe @f + mov ebx, [esp+44] +@@: + push ecx + lea esi, [ecx+eax+_FILE.buf] + mov ecx, ebx + mov edi, [esp+44] + rep movsb + pop ecx + mov [esp+40], edi + add [esp+28], ebx + add dword [ecx+_FILE.pos], ebx + adc dword [ecx+_FILE.pos+4], 0 + sub [esp+44], ebx + jz .ret +.nobuf0: + test dword [ecx+_FILE.pos], 2047 + jz .aligned + cmp dword [ecx+_FILE.bufsize], 0 + jnz .ret + lea ebx, [ecx+_FILE.fileinfo] + mov dword [ebx+12], 2048 + lea eax, [ecx+_FILE.buf] + mov dword [ebx+16], eax + mov eax, dword [ecx+_FILE.fioffset] + mov dword [ecx+_FILE.bufpos], eax + mov eax, dword [ecx+_FILE.fioffset+4] + mov dword [ecx+_FILE.bufpos+4], eax + call .doread + test eax, eax + jnz .ret + mov [ecx+_FILE.bufsize], ebx + mov eax, dword [ecx+_FILE.pos] + and eax, 2047 + sub ebx, eax + jbe .ret + cmp ebx, [esp+44] + jbe @f + mov ebx, [esp+44] +@@: + push ecx + lea esi, [ecx+eax+_FILE.buf] + mov ecx, ebx + mov edi, [esp+44] + rep movsb + pop ecx + add dword [ecx+_FILE.pos], ebx + adc dword [ecx+_FILE.pos+4], 0 + mov [esp+40], edi + add [esp+28], ebx + sub [esp+44], ebx + jz .ret + test dword [ecx+_FILE.pos], 2047 + jnz .ret +.aligned: + lea ebx, [ecx+_FILE.fileinfo] + mov eax, [esp+44] + and eax, not 2047 + jz .finish + and [ecx+_FILE.bufsize], 0 + mov [ebx+12], eax + mov eax, [esp+40] + mov [ebx+16], eax + call .doread + test eax, eax + jnz .ret + add dword [ecx+_FILE.pos], ebx + adc dword [ecx+_FILE.pos+4], 0 + add [esp+28], ebx + add [esp+40], ebx + sub [esp+44], ebx + jz .ret + cmp ebx, [ecx+_FILE.fisize] + jb .ret +.finish: + lea ebx, [ecx+_FILE.fileinfo] + mov dword [ebx+12], 2048 + lea eax, [ecx+_FILE.buf] + mov [ebx+16], eax + and [ecx+_FILE.bufsize], 0 + mov eax, dword [ecx+_FILE.fioffset] + mov dword [ecx+_FILE.bufpos], eax + mov eax, dword [ecx+_FILE.fioffset+4] + mov dword [ecx+_FILE.bufpos+4], eax + call .doread + test eax, eax + jnz .ret + mov [ecx+_FILE.bufsize], ebx + cmp ebx, [esp+44] + jb @f + mov ebx, [esp+44] +@@: + add [esp+28], ebx + add dword [ecx+_FILE.pos], ebx + adc dword [ecx+_FILE.pos+4], 0 + lea esi, [ecx+_FILE.buf] + mov edi, [esp+40] + mov ecx, ebx + rep movsb + popad + ret 12 +.doread: + mov eax, [ecx+_FILE.hPlugin] + test eax, eax + jz .native + push ecx + push [ecx+_FILE.fisize] + push [ecx+_FILE.fibuf] + push [ecx+_FILE.hFile] + call [eax+PluginInfo.read] + pop ecx + cmp eax, -1 + jz @f + mov ebx, eax + xor eax, eax + jmp .addpos +@@: + ret +.native: + push 70 + pop eax + int 0x40 + test eax, eax + jz .addpos + cmp eax, 6 + jnz @b + xor eax, eax +.addpos: + add dword [ecx+_FILE.fioffset], ebx + adc dword [ecx+_FILE.fioffset+4], 0 + ret + +; void __stdcall seek(HANDLE hFile, int method, __int64 newpos); +seek: + pushad + mov ecx, [esp+36] + mov eax, [esp+44] + mov edx, [esp+48] + cmp dword [esp+40], 1 + jb .set + ja .end + add eax, dword [ecx+_FILE.pos] + adc edx, dword [ecx+_FILE.pos+4] + jmp .set +.end: + add eax, dword [ecx+_FILE.attr+32] + adc edx, dword [ecx+_FILE.attr+36] +.set: + mov dword [ecx+_FILE.pos], eax + mov dword [ecx+_FILE.pos+4], edx + and eax, not 2047 + cmp eax, dword [ecx+_FILE.bufpos] + jnz @f + cmp edx, dword [ecx+_FILE.bufpos+4] + jz .bufposok +@@: + and [ecx+_FILE.bufsize], 0 + mov dword [ecx+_FILE.bufpos], eax + mov dword [ecx+_FILE.bufpos+4], edx +.bufposok: + cmp [ecx+_FILE.bufsize], 0 + jnz .ret + cmp eax, dword [ecx+_FILE.fioffset] + jnz @f + cmp edx, dword [ecx+_FILE.fioffset+4] + jz .ret +@@: + mov dword [ecx+_FILE.fioffset], eax + mov dword [ecx+_FILE.fioffset+4], edx + mov eax, [ecx+_FILE.hPlugin] + test eax, eax + jz @f + push dword [ecx+_FILE.fioffset+4] + push dword [ecx+_FILE.fioffset] + push [ecx+_FILE.hFile] + call [eax+PluginInfo.setpos] +@@: +.ret: + popad + ret 16 + +setpos_default: + push dword [esp+12] + push dword [esp+12] + push 0 + push dword [esp+16] + call seek + ret 12 + +; __int64 __stdcall filesize(HANDLE hFile); +filesize: + mov eax, [esp+4] + mov edx, dword [eax+_FILE.attr+36] + mov eax, dword [eax+_FILE.attr+32] + ret 4 + +; void __stdcall close(HANDLE hFile); +close: + pushad + mov ecx, [esp+24h] + mov eax, [ecx+_FILE.hPlugin] + test eax, eax + jz @f + push ecx + push [ecx+_FILE.hFile] + call [eax+PluginInfo.close] + pop ecx +@@: + call pgfree + popad + ret 4 + +getattr_default: + mov eax, 2 + ret 12 diff --git a/programs/fs/kfar/trunk/kfar.asm b/programs/fs/kfar/trunk/kfar.asm index d3049af20e..07c13d4e42 100644 --- a/programs/fs/kfar/trunk/kfar.asm +++ b/programs/fs/kfar/trunk/kfar.asm @@ -7,6 +7,9 @@ memsize dd mem dd stacktop dd 0, app_path +version equ '0.4' +version_dword equ 0*10000h + 40 + include 'lang.inc' include 'font.inc' include 'sort.inc' @@ -81,10 +84,18 @@ start: jz exit cmp [panel1_files], 0 jz exit - mov [panel1_sortmode], 0 ; sort by name - mov [panel2_sortmode], 0 - push 2 ; "средний" формат - pop eax + xor eax, eax + mov [panel1_hPlugin], eax + mov [panel1_parents], eax + mov [panel1_parents_sz], eax + mov [panel1_parents_alloc], eax + mov [panel2_hPlugin], eax + mov [panel2_parents], eax + mov [panel2_parents_sz], eax + mov [panel2_parents_alloc], eax + mov [panel1_sortmode], al ; sort by name + mov [panel2_sortmode], al + mov al, 2 ; "средний" формат mov [panel1_colmode], eax mov [panel2_colmode], eax mov [num_screens], 1 @@ -121,6 +132,28 @@ start: push dword app_path call [ini.get_int] mov [bConfirmDeleteIncomplete], al + push 2 + push aLeftViewMode + push aPanels + push app_path + call [ini.get_int] + cmp eax, 1 + jb @f + cmp eax, 4 + ja @f + mov [panel1_colmode], eax +@@: + push 2 + push aRightViewMode + push aPanels + push app_path + call [ini.get_int] + cmp eax, 1 + jb @f + cmp eax, 4 + ja @f + mov [panel2_colmode], eax +@@: mov ecx, 0x1000 call xpgalloc test eax, eax @@ -202,6 +235,11 @@ start: @@: loop .l3 .skip_shortcuts: +; load plugins + push enum_plugins_callback + push aPlugins + push app_path + call [ini.enum_keys] .noini: mov esi, def_left_dir mov edi, panel1_dir @@ -239,6 +277,86 @@ event: jz key ; button - we have only one button, close exit: +; close all screens +@@: + mov ecx, [num_screens] + mov eax, [screens] + mov ebp, [eax+ecx*8-4] + mov eax, [eax+ecx*8-8] + push ebp + call [eax+screen_vtable.OnExit] + pop ecx + call pgfree + dec [num_screens] + jnz @b +; unload all plugins + mov ecx, [num_plugins] + imul esi, ecx, PluginInfo.size + add esi, [plugins] +.unload: + dec ecx + js .unload_done + sub esi, PluginInfo.size + push ecx esi + call [esi+PluginInfo.unload] + pop esi ecx + jmp .unload +.unload_done: +if 0 ; commented due to bug in libini + cmp [ini.set_int], aIniSetInt + jz .nosave + push [panel1_colmode] + push aLeftViewMode + push aPanels + push app_path + call [ini.set_int] + push [panel2_colmode] + push aRightViewMode + push aPanels + push app_path + call [ini.set_int] +.nosave: +end if +if CHECK_FOR_LEAKS + mov ecx, [panel1_files] + call pgfree + mov ecx, [panel2_files] + call pgfree + mov ecx, [screens] + call pgfree + mov ecx, [associations] + call pgfree + mov ecx, [console_data_ptr] + call pgfree + mov ecx, [MemForImage] + call pgfree + mov esi, FolderShortcuts + push 10 + pop ecx +@@: + lodsd + test eax, eax + jnz @f + loop @b + jmp .nofreefs +@@: + mov ecx, eax + call pgfree + mov ecx, [plugins] + call pgfree + mov ecx, [panel1_parents] + call pgfree + mov ecx, [panel2_parents] + call pgfree +.nofreefs: + mov eax, [numallocatedregions] + test eax, eax + jz @f + mov edi, allocatedregions + int3 + jmp $ +@@: +end if or eax, -1 int 40h redraw: @@ -640,6 +758,182 @@ enum_associations_callback: xor eax, eax ret 12 +enum_plugins_callback: +; LongBool __stdcall callback(f_name,sec_name,key_name); +; [esp+4] = f_name, [esp+8] = sec_name, [esp+12] = key_name + push nullstr + push 1024 + push saved_file_name + push dword [esp+12+12] + push dword [esp+16+8] + push dword [esp+20+4] + call [ini.get_str] + test eax, eax + jnz .ret + mov esi, saved_file_name + cmp byte [esi], '/' + jz .absolute +; convert path to absolute + mov edi, execdata + push esi +@@: + lodsb + stosb + test al, al + jnz @b + pop edi + mov esi, app_path + push esi + xor ecx, ecx +@@: + lodsb + test al, al + jz @f + cmp al, '/' + jnz @b + mov ecx, esi + jmp @b +@@: + pop esi + sub ecx, esi + rep movsb + mov esi, execdata +.z: + cmp word [esi], '.' + jz .ret + cmp word [esi], './' + jnz @f + add esi, 2 + jmp .z +@@: + cmp word [esi], '..' + jnz .c + cmp byte [esi+2], 0 + jz .ret + cmp byte [esi+2], '/' + jnz .c + add esi, 3 +@@: + dec edi + cmp edi, saved_file_name + jbe .ret + cmp byte [edi-1], '/' + jnz @b + jmp .z +.c: + lodsb + stosb + test al, al + jz @f + cmp edi, saved_file_name+1024 + jb .c + mov esi, execdata + call load_dll_and_import.big +.ret: + mov al, 1 + ret 12 +@@: +.absolute: +; allocate space for plugin info + mov eax, [num_plugins] + inc eax + mov [num_plugins], eax + imul ecx, eax, PluginInfo.size + cmp ecx, [alloc_plugins] + jbe .norealloc + mov edx, [plugins] + call xpgrealloc + test eax, eax + jnz @f +.dec_ret: + dec [num_plugins] + jmp .ret +@@: + mov [plugins], eax + lea eax, [ecx+0xFFF] + and eax, not 0xFFF + mov [alloc_plugins], eax +.norealloc: + mov esi, [plugins] + lea esi, [esi+ecx-PluginInfo.size] +; load plugin DLL + or ebp, -1 + mov eax, saved_file_name + call load_dll_and_import.do + test eax, eax + jnz .dec_ret +; find exported functions + mov eax, aVersion + call load_dll_and_import.find_exported_function + jnc @f + xor eax, eax +@@: +MIN_INTERFACE_VER = 1 +MAX_INTERFACE_VER = 1 + cmp eax, MIN_INTERFACE_VER + jae @f + cmp eax, MAX_INTERFACE_VER + jbe @f + push aIncompatibleVersion +.cantload: + push saved_file_name + push aCannotLoadPlugin + mov eax, esp + push ContinueBtn + push 1 + push eax + push 3 + call SayErr + add esp, 12 + jmp .dec_ret +@@: + mov edi, esi + mov esi, plugin_exported +.import: + lodsd + test eax, eax + jz .import_done + call load_dll_and_import.find_exported_function + jnc @f + mov eax, [esi-4+plugin_exported_default-plugin_exported] +@@: + stosd + jmp .import +.import_done: +; initialize plugin + mov eax, aPluginLoad + call load_dll_and_import.find_exported_function + jc .ok + push kfar_info + call eax + cmp eax, 1 + jb .ok + ja .dec_ret + push aInitFailed + jmp .cantload +.ok: + mov al, 1 + ret 12 + +plugin_unload_default: + ret + +OpenFilePlugin_default: +GetFiles_default: + xor eax, eax + ret 20 + +ClosePlugin_default: + ret 4 + +GetOpenPluginInfo_default: + ret 8 + +SetFolder_default: +open_default: + xor eax, eax + ret 12 + new_screen: ; in: ecx=sizeof(screen data), edx->vtable ; out: ebp=pointer or NULL, eax!=0 if successful @@ -967,6 +1261,152 @@ panels_OnKey: call get_curfile_folder_entry test byte [ecx], 10h jnz .enter_folder +; todo: add handling on plugin panel + cmp [ebp + panel1_hPlugin - panel1_data], 0 + jnz .ret +; generate full file name + lea esi, [ebp + panel1_dir - panel1_data] + mov edi, execdata +@@: + lodsb + test al, al + jz @f + stosb + cmp edi, execdataend-1 + jae .bigfilename + jmp @b +@@: + lea esi, [ecx+40] + mov al, '/' + stosb +@@: + lodsb + stosb + cmp edi, execdataend + ja .bigfilename + test al, al + jnz @b +; try to open file and look for all plugins + push O_READ + push execdata + call open + test eax, eax + jz .noplugins ; if can't open, just try to execute + mov esi, eax ; save handle + push filedata_buffer_size + push filedata_buffer + push esi + call read + mov edi, eax ; save size of read data +; test for Kolibri executable + cmp eax, 24h + jb .enter.noexec + cmp dword [filedata_buffer], 'MENU' + jnz @f + cmp word [filedata_buffer+4], 'ET' + jnz @f +.close_run: + push esi + call close + jmp .run_app +@@: + cmp dword [filedata_buffer], 'KPCK' + jnz @f + cmp dword [filedata_buffer+12], 0x26914601 + jz .close_run +@@: +.enter.noexec: + mov ecx, [num_plugins] + mov edx, [plugins] + sub edx, PluginInfo.size +.plugloop: + add edx, PluginInfo.size + dec ecx + js .plugdone + pushad + push edi + push filedata_buffer + call get_curfile_folder_entry + push ecx + push execdata + push esi + call [edx+PluginInfo.OpenFilePlugin] + mov [esp+28], eax + popad + test eax, eax + jz .plugloop + cmp eax, -1 + jnz .pluginok + push esi + call close + ret +.pluginok: +; save current directory and set root directory of hPlugin + mov edi, eax ; save handle + mov esi, execdata +@@: + lodsb + test al, al + jnz @b + sub esi, execdata-9 +; allocate esi bytes in buffer 'parents' + mov ecx, [ebp + panel1_parents_sz - panel1_data] + add ecx, esi + cmp ecx, [ebp + panel1_parents_alloc - panel1_data] + jbe .enter.norealloc + push edx + mov edx, [ebp + panel1_parents - panel1_data] + call xpgrealloc + pop edx + test eax, eax + jnz @f + push edi + call [edx+PluginInfo.ClosePlugin] + ret +@@: + mov [ebp + panel1_parents - panel1_data], eax +.enter.norealloc: + mov [ebp + panel1_parents_sz - panel1_data], ecx +; save current state to the end of buffer + sub ecx, esi + add ecx, [ebp + panel1_parents - panel1_data] + xchg edx, [ebp + panel1_hPlugin - panel1_data] + mov [ecx], edx + xchg edi, [ebp + panel1_hFile - panel1_data] + mov [ecx+4], edi + mov byte [ecx+8], 0 + lea edi, [ecx+9] + lea ecx, [esi-9] + mov esi, execdata + rep movsb + mov word [ebp + panel1_dir - panel1_data], '/' + mov eax, [ebp + panel1_hPlugin - panel1_data] + lea ebx, [ebp + panel1_plugin_info - panel1_data] + and dword [ebx], 0 + push ebp + push ebx + push [ebp + panel1_hFile - panel1_data] + call [eax+PluginInfo.GetOpenPluginInfo] + pop ebp + call get_curfile_folder_entry + mov esi, ecx + mov edi, left_dotdot_entry + cmp ebp, panel1_data + jz @f + add edi, right_dotdot_entry-left_dotdot_entry +@@: + mov ecx, 10 + rep movsd + mov byte [edi-40], 10h ; attributes: folder + mov eax, '..' + stosd + jmp .reread +.plugdone: + push esi + call close +.noplugins: +; run program or association + call get_curfile_folder_entry call find_extension jc .run_app .run_association: @@ -996,27 +1436,6 @@ panels_OnKey: mov [execptr], execdata and [execparams], 0 .dorun: - lea esi, [ebp + panel1_dir - panel1_data] - mov edi, execdata -@@: - lodsb - test al, al - jz @f - stosb - cmp edi, execdataend-1 - jae .bigfilename - jmp @b -@@: - lea esi, [ecx+40] - mov al, '/' - stosb -@@: - lodsb - stosb - cmp edi, execdataend - ja .bigfilename - test al, al - jnz @b ; for fasm call - special handling, because ; 1) fasm command line convention is different : fasm infile,outfile[,path] rather than tinypad infile ; 2) fasm will probably create new file in directory, so we want to reload panel data @@ -1096,9 +1515,6 @@ panels_OnKey: push 1 push eax push 2 - push -1 - push -1 - push dword aError call SayErr pop eax pop eax @@ -1133,9 +1549,6 @@ panels_OnKey: push 1 push eax push 1 - push -1 - push -1 - push dword aError call SayErr pop eax ret @@ -1143,7 +1556,13 @@ panels_OnKey: mov eax, aCmdLineTooBig jmp .l2 .bigfoldername2: - mov byte [ecx], 0 + mov esi, prev_dir + lea edi, [ebp + panel1_dir - panel1_data] +@@: + lodsb + stosb + test al, al + jnz @b .bigfoldername: mov eax, aFolderNameTooBig jmp .l2 @@ -1167,7 +1586,6 @@ panels_OnKey: cmp esi, edx pop esi jae .bigfoldername - mov ecx, edi mov al, '/' cmp [edi-1], al jz @f @@ -1179,6 +1597,28 @@ panels_OnKey: stosb test al, al jnz @b + mov eax, [ebp + panel1_hPlugin - panel1_data] + test eax, eax + jz .reread + push ebp + lea esi, [ebp + panel1_dir - panel1_data] + push esi + add ecx, 40 + push ecx + push [ebp + panel1_hFile - panel1_data] + call [eax+PluginInfo.SetFolder] + pop ebp + test al, al + jnz .reread + mov esi, prev_dir + lea edi, [ebp + panel1_dir - panel1_data] +@@: + lodsb + stosb + test al, al + jnz @b +.retd: + ret .reread: call read_folder .done_cmdbar: @@ -1186,6 +1626,14 @@ panels_OnKey: jmp .done_redraw .dotdot: lea edi, [ebp + panel1_dir - panel1_data] + cmp word [edi], '/' + jnz .dotdot_noroot + cmp [ebp + panel1_hPlugin - panel1_data], 0 + jz .retd + call close_plugin_panel + jmp .dotdot +.dotdot_noroot: + mov edx, edi mov al, 0 or ecx, -1 repnz scasb @@ -1195,11 +1643,37 @@ panels_OnKey: repnz scasb cld inc edi - mov byte [edi], 0 + cmp edi, edx + jnz @f inc edi +@@: + push dword [edi] + mov byte [edi], 0 push edi + mov eax, [ebp + panel1_hPlugin - panel1_data] + test eax, eax + jz .dotdot_native + push ebp + lea esi, [ebp + panel1_dir - panel1_data] + push esi + push aDotDot + push [ebp + panel1_hFile - panel1_data] + call [eax+PluginInfo.SetFolder] + pop ebp + test al, al + jnz .dotdot_native + pop edi + pop dword [edi] + ret +.dotdot_native: call read_folder pop edi + pop dword [edi] + push edi + cmp byte [edi], '/' + jnz @f + inc edi +@@: mov edx, [ebp + panel1_files - panel1_data] mov ecx, [ebp + panel1_numfiles - panel1_data] .scanloop: @@ -1228,6 +1702,8 @@ panels_OnKey: inc edx mov [ebp + panel1_start - panel1_data], edx .scandone: + pop edi + mov byte [edi], 0 jmp .done_cmdbar .ctrl_f39: sub al, 0x3D @@ -1356,6 +1832,10 @@ panels_OnKey: @@: mov ecx, edx lea edi, [ebp + panel1_dir - panel1_data] + cmp [ebp + panel1_hPlugin - panel1_data], 0 + jz .find_cur_drive_loop + mov edi, [ebp + panel1_parents - panel1_data] + add edi, 8 .find_cur_drive_loop: push edi lea esi, [ecx+8] @@ -1391,15 +1871,22 @@ panels_OnKey: push [ebp + panel1_left - panel1_data] call menu_centered_in cmp eax, -1 - jz .ret2 - lea esi, [eax+8] + jnz @f + mov ecx, edx + call pgfree + ret +@@: + push eax + call close_plugin_panels lea edi, [ebp + panel1_dir - panel1_data] - push ecx esi edi + push edi mov esi, edi mov edi, prev_dir mov ecx, 1024/4 rep movsd - pop edi esi ecx + pop edi + pop esi + add esi, 8 @@: lodsb stosb @@ -1410,6 +1897,11 @@ panels_OnKey: call read_folder jmp .done_redraw .shift_f5: +; todo: copy to plugin panel + cmp [ebp + panel1_hPlugin - panel1_data], 0 + jz @f + ret +@@: mov esi, ebp cmp [ebp + panel1_selected_num - panel1_data], 0 jnz .f5_2 @@ -1429,9 +1921,23 @@ panels_OnKey: stosb jmp @b .f5: +; todo: copy to plugin panel mov esi, ebp xor esi, panel1_data xor panel2_data + cmp [esi + panel1_hPlugin - panel1_data], 0 + jz .f5_2 + ret .f5_2: + mov eax, [ebp + panel1_hPlugin - panel1_data] + mov [source_hModule], eax + mov eax, [ebp + panel1_hFile - panel1_data] + mov [source_hPlugin], eax + mov eax, left_dotdot_entry + cmp ebp, panel1_data + jz @f + add eax, right_dotdot_entry-left_dotdot_entry +@@: + mov [default_attr], eax add esi, panel1_dir - panel1_data mov edi, CopyDestEditBuf mov eax, CopyDestEditBuf.length @@ -1699,9 +2205,6 @@ end if push 1 push eax push 2 - push -1 - push -1 - push aError call SayErr pop eax pop eax @@ -1767,6 +2270,9 @@ end if mov [bDestIsFolder], dl mov [copy_bSkipAll], 0 mov [copy_bSkipAll2], 0 + mov [copy_bSkipAll3], 0 + test [ebp + panel1_plugin_flags - panel1_data], 2 + jnz .copy_GetFiles cmp [ebp + panel1_selected_num - panel1_data], 0 jnz .f5_selected3 call copy_file @@ -1799,6 +2305,43 @@ end if loop .f5_selected_copyloop .f5_multiple_cancel: jmp .copydone +.copy_GetFiles: + mov ecx, [ebp + panel1_selected_num - panel1_data] + cmp ecx, 1 + adc ecx, 0 + shl ecx, 2 + call xpgalloc + test eax, eax + jnz @f + ret +@@: + push ebp eax ; save + push copy_AddDir ; adddir + push copy_AddFile ; addfile + push eax ; items + shr ecx, 2 + push ecx ; NumItems + push [ebp + panel1_hFile - panel1_data] + mov edi, eax + call get_curfile_folder_entry + mov [edi], ecx + cmp [ebp + panel1_selected_num - panel1_data], 0 + jz .cgf1 + mov esi, [ebp + panel1_files - panel1_data] + mov ecx, [ebp + panel1_numfiles - panel1_data] +.cgf0: + lodsd + test byte [eax+303], 1 + jz @f + stosd +@@: + loop .cgf0 +.cgf1: + mov eax, [ebp + panel1_hPlugin - panel1_data] + call [eax+PluginInfo.GetFiles] + pop ecx ebp + call pgfree + jmp .copydone .f3: call view_file @@ -1849,8 +2392,6 @@ end if push 2 push eax push 2 - push -1 - push -1 push aDeleteCaption call Message add esp, 8 @@ -1871,6 +2412,11 @@ end if .f8_multiple_cancel: jmp .copydone .f8: +; todo: delete files from plugin panel + cmp [ebp + panel1_hPlugin - panel1_data], 0 + jz @f + ret +@@: cmp [ebp + panel1_selected_num - panel1_data], 0 jnz .f8_has_selected call get_curfile_folder_entry @@ -1901,8 +2447,6 @@ end if push 2 push eax push 2 - push -1 - push -1 push aDeleteCaption call Message add esp, 8 @@ -1975,6 +2519,11 @@ end if @@: jmp .done_redraw .menu: +; todo: context menu for plugin panel + cmp [ebp + panel1_hPlugin - panel1_data], 0 + jz @f + ret +@@: ; display context menu ; ignore folders call get_curfile_folder_entry @@ -2253,8 +2802,10 @@ end if jnz @f ret @@: + push eax + call close_plugin_panels lea esi, [ebp + panel1_dir - panel1_data] - push eax esi + push esi mov edi, prev_dir @@: lodsb @@ -2383,6 +2934,113 @@ end if .galoopdone: jmp .done_redraw +@@: + call close_plugin_panel +close_plugin_panels: + cmp [ebp + panel1_hPlugin - panel1_data], 0 + jnz @b + ret + +close_plugin_panel: +; close plugin and restore old directory + mov esi, [ebp + panel1_parents - panel1_data] + add esi, [ebp + panel1_parents_sz - panel1_data] +@@: + dec esi + cmp byte [esi-1], 0 + jnz @b + push esi + lea edi, [ebp + panel1_dir - panel1_data] +@@: + lodsb + stosb + test al, al + jnz @b + pop esi + sub esi, 9 + mov edx, [esi] ; hPlugin + mov ebx, [esi+4] ; hFile + sub esi, [ebp + panel1_parents - panel1_data] + mov [ebp + panel1_parents_sz - panel1_data], esi + xchg edx, [ebp + panel1_hPlugin - panel1_data] + xchg ebx, [ebp + panel1_hFile - panel1_data] + push edx ebx + lea ebx, [ebp + panel1_plugin_info - panel1_data] + and dword [ebx], 0 + mov eax, [ebp + panel1_hPlugin - panel1_data] + test eax, eax + jz @f + push ebp + push ebx + push [ebp + panel1_hFile - panel1_data] + call [eax+PluginInfo.GetOpenPluginInfo] + pop ebp +@@: + pop ebx edx + +close_handle_if_unused: +; edx=hPlugin, ebx=hFile + push ebp + xor ecx, ecx +@@: + mov eax, [screens] + mov ebp, [eax+ecx*8+4] + mov eax, [eax+ecx*8] + call [eax+screen_vtable.IsHandleUsed] + jz .used + inc ecx + cmp ecx, [num_screens] + jb @b + push ebx + call [edx+PluginInfo.ClosePlugin] +.used: + pop ebp + ret + +panels_IsHandleUsed: +; edx=hPlugin, ebx=hFile + mov ebp, panel1_data + call .1 + jz .ret + mov ebp, panel2_data + +.1: + cmp edx, [ebp+panel1_hPlugin-panel1_data] + jnz @f + cmp ebx, [ebp+panel1_hFile-panel1_data] + jz .ret +@@: + mov esi, [ebp + panel1_parents_sz - panel1_data] + test esi, esi + jnz @f + inc esi +.ret: + ret +@@: + add esi, [ebp + panel1_parents - panel1_data] +@@: + dec esi + cmp byte [esi-1], 0 + jnz @b + sub esi, 9 + cmp edx, [esi] ; hPlugin + jnz .no + mov ebx, [esi+4] ; hFile + jz .ret +.no: + cmp esi, [ebp + panel1_parents - panel1_data] + jnz @b + inc esi + ret + +panels_OnExit: +; close plugin panels + mov ebp, panel1_data + call close_plugin_panels + mov ebp, panel2_data + call close_plugin_panels + ret + panels_OnRedraw: call draw_cmdbar mov ebp, panel1_data @@ -2458,9 +3116,40 @@ else end if sub ecx, 13 mov ebp, [active_panel] - lea esi, [ebp + panel1_dir - panel1_data] push 3 pop edx + cmp [ebp + panel1_hPlugin - panel1_data], 0 + jz .native + mov esi, [ebp + panel1_parents - panel1_data] + add esi, [ebp + panel1_parents_sz - panel1_data] +@@: + dec esi + cmp byte [esi-1], 0 + jz @f + cmp byte [esi-1], '/' + jnz @b +@@: + push ecx edi + shr ecx, 1 +@@: + lodsb + test al, al + jz @f + stosb + loop @b +@@: + sub edi, [esp] + sub [esp+4], edi + add [esp], edi + pop edi ecx + lea esi, [ebp + panel1_dir - panel1_data] + cmp byte [esi+1], 0 + jnz @f + inc esi +@@: + jmp .main +.native: + lea esi, [ebp + panel1_dir - panel1_data] @@: lodsb stosb @@ -2477,6 +3166,7 @@ end if dec esi dec edi @@: +.main: push esi @@: lodsb @@ -2518,11 +3208,11 @@ end if jz .nodir cmp esi, [esp] jae @b + mov esi, [esp+4] mov al, '/' stosb dec ecx jz .nodir - mov esi, [esp+4] @@: cmp esi, [esp+8] jb .nodir @@ -3058,6 +3748,44 @@ calc_colwidths: and dword [edi], 0 ret +GetPanelTitle_default: + mov edi, [esp+8] + mov ecx, 1024 + mov esi, [esp+12] + test esi, esi + jz .nohost + mov edx, esi +@@: + lodsb + test al, al + jz @f + cmp al, '/' + jnz @b + mov edx, esi + jmp @b +@@: + mov esi, edx +@@: + lodsb + stosb + test al, al + loopnz @b + dec edi + inc ecx +.nohost: + mov esi, [esp+16] + cmp word [esi], '/' + jz .nodir +@@: + lodsb + stosb + test al, al + loopnz @b + dec edi +.nodir: + mov byte [edi], 0 + ret 10h + draw_panel: mov eax, [ebp + panel1_left - panel1_data] mov edx, [ebp + panel1_top - panel1_data] @@ -3182,6 +3910,24 @@ draw_panel: jnz .columns_loop ; Заголовок панели (текущая папка) lea esi, [ebp + panel1_dir - panel1_data] + mov eax, [ebp + panel1_hPlugin - panel1_data] + test eax, eax + jz .native + push ebp + push esi + mov esi, [ebp + panel1_parents - panel1_data] + add esi, [ebp + panel1_parents_sz - panel1_data] +@@: + dec esi + cmp byte [esi-1], 0 + jnz @b + push esi + push execdata + push [ebp + panel1_hFile - panel1_data] + call [eax+PluginInfo.GetPanelTitle] + pop ebp + mov esi, execdata +.native: mov edi, cur_header mov ecx, [ebp + panel1_width - panel1_data] sub ecx, 7 @@ -4038,10 +4784,30 @@ read_folder: mov dword [ebp + panel1_selected_size - panel1_data], eax mov dword [ebp + panel1_selected_size+4 - panel1_data], eax .retry: + mov eax, [ebp + panel1_hPlugin - panel1_data] + test eax, eax + jz .native + mov ecx, [dirinfo.size] + test [ebp + panel1_plugin_flags - panel1_data], 1 + jz @f + dec ecx ; reserve one entry for '..' +@@: + push ebp + push [dirinfo.dirdata] + push ecx + push 0 + push [ebp + panel1_hFile - panel1_data] + call [eax + PluginInfo.ReadFolder] + pop ebp + mov ebx, [dirinfo.dirdata] + mov ebx, [ebx+4] + jmp .read +.native: push 70 pop eax mov ebx, dirinfo int 40h +.read: test eax, eax jz .ok cmp eax, 6 @@ -4061,14 +4827,14 @@ read_folder: push 2 push eax push 3 - push -1 - push -1 - push dword aError call SayErr add esp, 5*4 test eax, eax jz .retry .dont_notify: +; If not on plugin panel, try to return to previous directory + cmp [ebp + panel1_hPlugin - panel1_data], 0 + jnz @f mov esi, prev_dir cmp byte [esi], 0 jz @f @@ -4079,6 +4845,7 @@ read_folder: ret @@: mov [bSilentFolderMode], 1 ; enter silent mode +; Try to read parent folder mov esi, [dirinfo.name] xor edx, edx .up1: @@ -4091,11 +4858,27 @@ read_folder: lea edi, [esi-1] jmp .up1 .up1done: + cmp [ebp + panel1_hPlugin - panel1_data], 0 + jz .4 + cmp edx, 1 + ja .up +; чтение с панели плагина обломалось по полной +; при этом мы уже в корне +; делаем вид, что функция чтения вернула 0 элементов +; (если нужен вход "..", он будет добавлен автоматически) + xor ebx, ebx ; 0 items read + mov eax, [dirinfo.dirdata] + mov [eax+8], ebx ; 0 items total + jmp .ok +.4: cmp edx, 2 jbe .noup +.up: stosb jmp read_folder .noup: +; There is no parent folder, and we are not on plugin panel +; Try to read ramdisk mov esi, [dirinfo.name] mov edi, esi lodsd @@ -4142,16 +4925,16 @@ read_folder: mov [prev_dir], 0 jmp read_folder .readdone: - and [ebp + panel1_start - panel1_data], 0 - and [ebp + panel1_index - panel1_data], 0 - and [ebp + panel1_start - panel1_data], 0 + xor edx, edx + mov [ebp + panel1_start - panel1_data], edx + mov [ebp + panel1_index - panel1_data], edx + mov [ebp + panel1_start - panel1_data], edx mov edi, [ebp + panel1_files - panel1_data] mov eax, [ebp + panel1_nfa - panel1_data] lea eax, [edi + eax*4 + 32] mov ecx, [eax-32+4] test ecx, ecx jz .loopdone - xor edx, edx ; Игнорируем специальные входы, соответствующие папке '.' и метке тома .ptrinit: cmp word [eax+40], '.' @@ -4192,6 +4975,58 @@ read_folder: .dotdot: ; подсветка ; call insert_last_dot + call highlight_init +; call delete_last_dot +.loopcont: + add eax, 304 + dec ecx + jnz .ptrinit +.loopdone: + push edi + sub edi, [ebp + panel1_files - panel1_data] + shr edi, 2 + mov [ebp + panel1_numfiles - panel1_data], edi + pop edi + test edx, edx + jnz @f + test [ebp + panel1_plugin_flags - panel1_data], 1 + jz @f + mov ecx, [ebp + panel1_numfiles - panel1_data] + inc [ebp + panel1_numfiles - panel1_data] + lea esi, [edi-4] + std + rep movsd + cld + mov eax, left_dotdot_entry + cmp ebp, panel1_data + jz .zq + add eax, right_dotdot_entry-left_dotdot_entry +.zq: + stosd + call highlight_init +@@: +; Сортировка +sort_files: + movzx eax, [ebp + panel1_sortmode - panel1_data] + mov ebx, [compare_fns + eax*4] +.mode: + mov edx, [ebp + panel1_files - panel1_data] + mov ecx, [ebp + panel1_numfiles - panel1_data] + jecxz .skip + mov eax, [edx] + cmp word [eax+40], '..' + jnz .nodotdot + cmp byte [eax+42], 0 + jnz .nodotdot + dec ecx + add edx, 4 +.nodotdot: + call sort +.skip: + mov [bSilentFolderMode], 0 ; leave silent mode + ret + +highlight_init: pushad mov ebp, eax lea esi, [ebp+40] @@ -4256,35 +5091,7 @@ read_folder: mov ah, [panel_selected_cursor_color] mov [ebp+7], ah .doname: -; call delete_last_dot popad -.loopcont: - add eax, 304 - dec ecx - jnz .ptrinit -.loopdone: - sub edi, [ebp + panel1_files - panel1_data] - shr edi, 2 - mov [ebp + panel1_numfiles - panel1_data], edi -.done: -; Сортировка -sort_files: - movzx eax, [ebp + panel1_sortmode - panel1_data] - mov ebx, [compare_fns + eax*4] - mov edx, [ebp + panel1_files - panel1_data] - mov ecx, [ebp + panel1_numfiles - panel1_data] - jecxz .skip - mov eax, [edx] - cmp word [eax+40], '..' - jnz .nodotdot - cmp byte [eax+42], 0 - jnz .nodotdot - dec ecx - add edx, 4 -.nodotdot: - call sort -.skip: - mov [bSilentFolderMode], 0 ; leave silent mode ret compare_name: @@ -4689,7 +5496,12 @@ compare_accessed_rev: stc ret +ReadFolder_default: + mov eax, 2 + ret 10h + if 0 +; Following subroutines work, but are slow match_mask: ; in: esi->name, edi->mask ; out: CF clear <=> match @@ -5273,7 +6085,7 @@ find_extension: pop esi ret -header db 'Kolibri Far 0.35',0 +header db 'Kolibri Far ',version,0 nomem_draw db 'No memory for redraw.',0 .size = $ - nomem_draw @@ -5703,6 +6515,8 @@ screen_vtable: .OnKey dd ? .keybar dd ? .getname dd ? + .OnExit dd ? + .IsHandleUsed dd ? end virtual panels_vtable: @@ -5710,12 +6524,16 @@ panels_vtable: dd panels_OnKey dd keybar_panels dd panels_getname + dd panels_OnExit + dd panels_IsHandleUsed viewer_vtable: dd viewer_OnRedraw dd viewer_OnKey dd keybar_viewer dd viewer_getname + dd viewer_OnExit + dd viewer_IsHandleUsed ; additions to this table require changes in tools.inc::get_error_msg errors1: @@ -6293,6 +7111,7 @@ DeleteErrorBtn: ContinueBtn: dd aContinue +aCannotOpenFile_ptr dd aCannotOpenFile if lang eq ru aDeleteCaption db 'Удаление',0 aConfirmDeleteText db 'Вы хотите удалить',0 @@ -6354,6 +7173,7 @@ aSize db 6,' aDate db 4,'Дата' aTime db 5,'Время' aCannotLoadDLL db 'Не могу загрузить DLL',0 +aCannotLoadPlugin db 'Не могу загрузить плагин',0 aInvalidDLL db 'Файл не найден или имеет неверный формат',0 aMissingExport db 'Необходимая функция не найдена',0 aInitFailed db 'Ошибка при инициализации',0 @@ -6361,6 +7181,8 @@ aIncompatibleVersion db ' aTables db 'Таблицы',0 aSelect db 'Пометить',0 aDeselect db 'Снять',0 +aCannotOpenFile db 'Ошибка при открытии файла',0 +aCannotSetFolder db 'Не могу зайти в папку',0 else aDeleteCaption db 'Delete',0 aConfirmDeleteText db 'Do you wish to delete',0 @@ -6426,6 +7248,7 @@ aSize db 4,'Size' aDate db 4,'Date' aTime db 4,'Time' aCannotLoadDLL db 'Cannot load DLL',0 +aCannotLoadPlugin db 'Cannot load plugin',0 aInvalidDLL db 'File is not found or invalid',0 aMissingExport db 'Required function is not present',0 aInitFailed db 'Initialization failed',0 @@ -6433,11 +7256,15 @@ aIncompatibleVersion db 'Incompatible version',0 aTables db 'Tables',0 aSelect db 'Select',0 aDeselect db 'Deselect',0 +aCannotOpenFile db 'Cannot open the file',0 +aCannotSetFolder db 'Cannot enter to folder',0 end if aOk db 'OK',0 aNoMemory db 'No memory!' nullstr db 0 +aUntitled db 'untitled',0 +aDotDot db '..',0,0 standard_dll_path: libini_name db '/sys/dll/' standard_dll_path_size = $ - standard_dll_path @@ -6447,13 +7274,33 @@ aLibInit db 'lib_init',0 aVersion db 'version',0 aIniGetInt db 'ini.get_int',0 aIniGetStr db 'ini.get_str',0 +aIniSetInt db 'ini.set_int',0 aIniEnumKeys db 'ini.enum_keys',0 +aPluginLoad db 'plugin_load',0 +aPluginUnload db 'plugin_unload',0 +aGetattr db 'getattr',0 +aOpen db 'open',0 +aRead db 'read',0 +aSetpos db 'setpos',0 +aClose db 'close',0 +aOpenFilePlugin db 'OpenFilePlugin',0 +aClosePlugin db 'ClosePlugin',0 +aReadFolder db 'ReadFolder',0 +aSetFolder db 'SetFolder',0 +aGetOpenPluginInfo db 'GetOpenPluginInfo',0 +aGetPanelTitle db 'GetPanelTitle',0 +aGetFiles db 'GetFiles',0 aConfirmations db 'Confirmations',0 aConfirmDelete db 'Delete',0 aConfirmDeleteIncomplete db 'DeleteIncomplete',0 +aPanels db 'Panels',0 +aLeftViewMode db 'LeftViewMode',0 +aRightViewMode db 'RightViewMode',0 + aAssociations db 'Associations',0 +aPlugins db 'Plugins',0 aMenu db 'Menu',0 aFolderShortcuts db 'FolderShortcuts',0 aShortcut db 'Shortcut' @@ -6464,8 +7311,86 @@ ini_import: ini.get_int dd aIniGetInt ini.get_str dd aIniGetStr ini.enum_keys dd aIniEnumKeys +ini.set_int dd aIniSetInt dd 0 +plugin_exported: + dd aPluginUnload + dd aGetattr + dd aOpen + dd aRead + dd aSetpos + dd aClose + dd aOpenFilePlugin + dd aClosePlugin + dd aReadFolder + dd aSetFolder + dd aGetOpenPluginInfo + dd aGetPanelTitle + dd aGetFiles + dd 0 +plugin_exported_default: + dd plugin_unload_default + dd getattr_default + dd open_default + dd read + dd setpos_default + dd close + dd OpenFilePlugin_default + dd ClosePlugin_default + dd ReadFolder_default + dd SetFolder_default + dd GetOpenPluginInfo_default + dd GetPanelTitle_default + dd GetFiles_default + +kfar_info: + dd .size + dd version_dword + dd open + dd read + dd -1 ; write: to be implemented + dd seek + dd -1 ; flush: to be implemented + dd filesize + dd close + dd xpgalloc + dd xpgrealloc + dd pgfree + dd getfreemem + dd libini_alloc + dd libini_realloc + dd libini_free + dd menu + dd menu_centered_in + dd DialogBox + dd SayErr + dd Message + dd cur_width +.size = $ - kfar_info + +plugins dd 0 +num_plugins dd 0 +alloc_plugins dd 0 + +virtual at 0 +PluginInfo: +.unload dd ? +.getattr dd ? +.open dd ? +.read dd ? +.setpos dd ? +.close dd ? +.OpenFilePlugin dd ? +.ClosePlugin dd ? +.ReadFolder dd ? +.SetFolder dd ? +.GetOpenPluginInfo dd ? +.GetPanelTitle dd ? +.GetFiles dd ? +.size = $ +end virtual + virtual at 0 PanelMode: ; up to 16 columns on one panel @@ -6592,12 +7517,19 @@ panel1_sortmode db ? panel1_nfa dd ? panel1_numfiles dd ? panel1_files dd ? -panel1_colmode dd ? -panel1_colwidths rd 16+1 -panel1_total_num dd ? -panel1_total_size dq ? -panel1_selected_num dd ? -panel1_selected_size dq ? +panel1_hPlugin dd ? +panel1_hFile dd ? +panel1_parents dd ? +panel1_parents_sz dd ? +panel1_parents_alloc dd ? +panel1_colmode dd ? +panel1_colwidths rd 16+1 +panel1_total_num dd ? +panel1_total_size dq ? +panel1_selected_num dd ? +panel1_selected_size dq ? +panel1_plugin_info: +panel1_plugin_flags dd ? panel1_dir rb 1024 panel2_data: @@ -6614,12 +7546,19 @@ panel2_sortmode db ? panel2_nfa dd ? panel2_numfiles dd ? panel2_files dd ? -panel2_colmode dd ? -panel2_colwidths rd 16+1 -panel2_total_num dd ? -panel2_total_size dq ? -panel2_selected_num dd ? -panel2_selected_size dq ? +panel2_hPlugin dd ? +panel2_hFile dd ? +panel2_parents dd ? +panel2_parents_sz dd ? +panel2_parents_alloc dd ? +panel2_colmode dd ? +panel2_colwidths rd 16+1 +panel2_total_num dd ? +panel2_total_size dq ? +panel2_selected_num dd ? +panel2_selected_size dq ? +panel2_plugin_info: +panel2_plugin_flags dd ? panel2_dir rb 1024 ;console_data rb max_width*max_height*2 @@ -6670,6 +7609,10 @@ num_screens dd ? active_screen_vtable dd ? active_screen_data dd ? +default_attr dd ? +left_dotdot_entry rb 40+3 ; 40 bytes for attributes + '..' +right_dotdot_entry rb 40+3 + aConfirmDeleteTextBuf rb aConfirmDeleteTextMax + 1 CopySourceTextBuf rb 512 CopyDestEditBuf rb 12+512+1 @@ -6686,6 +7629,12 @@ layout rb 128 copy_buffer_size = 65536 copy_buffer rb copy_buffer_size +filedata_buffer_size = 1024 +filedata_buffer rb filedata_buffer_size + +source_hModule dd ? +source_hPlugin dd ? +source_hFile dd ? ; data for directory delete ; If directory nested level is >1024, then its full name is too big, ; so we see the overflow when creating full name (we check for this!) @@ -6701,6 +7650,7 @@ copy_dir_query_area = del_dir_query_area del_bSkipAll db ? ; for directory errors label copy_bSkipAll byte at del_bSkipAll copy_bSkipAll2 db ? ; for file read/write errors +copy_bSkipAll3 db ? ; for SetFolder errors bEndSlash db ? bDestIsFolder db ? @@ -6708,7 +7658,7 @@ bNeedRestoreName db ? ; stack align 4 - rb 512 + rb 32768 stacktop: mem: diff --git a/programs/fs/kfar/trunk/kfar.ini b/programs/fs/kfar/trunk/kfar.ini new file mode 100644 index 0000000000..e07888fe0f --- /dev/null +++ b/programs/fs/kfar/trunk/kfar.ini @@ -0,0 +1,43 @@ +[Associations] +asm=/rd/1/TinyPad; AsmMenu1,AsmMenu2 +inc=/rd/1/TinyPad +ini=/rd/1/TinyPad +txt=/rd/1/TinyPad +jpg=/rd/1/JpegView +jpeg=/rd/1/JpegView +gif=/rd/1/GIFVIEW; GifMenu1,MenuAnimage +wav=/rd/1/AC97SND +mp3=/rd/1/AC97SND +mid=/rd/1/MIDAMP +bmp=/rd/1/MV; BmpMenu1,MenuAnimage +png=/rd/1/@rcher +rtf=/rd/1/RtfRead +3ds=/rd/1/3d/view3ds +lif=/rd/1/demos/life2 +skn=/rd/1/desktop + +[Menu] +AsmMenu1=&Редактор,/rd/1/TinyPad +AsmMenu2=&Компилировать,/rd/1/develop/fasm +GifMenu1=&Просмотр,/rd/1/GIFVIEW +BmpMenu1=&Просмотр,/rd/1/MV +MenuAnimage=&Редактор,/rd/1/animage + +[Panels] +LeftViewMode=2 +RightViewMode=2 + +[FolderShortcuts] +# Можно определить до десяти ссылок на папки Shortcut0...Shortcut9, +# на такие папки можно сделать быстрый переход по RCtrl+<цифра> +Shortcut0=/rd/1 + +[Confirmations] +Delete=1 +DeleteIncomplete=0 + +# Слева от знака равенства можно ставить любое осмысленное или бессмысленное +# имя; справа - путь к плагину. +# Если путь не абсолютен, то он отсчитывается от папки с бинарником kfar. +[Plugins] +ArchiveReader=kfar_arc.obj diff --git a/programs/fs/kfar/trunk/kfar_arc/7z.inc b/programs/fs/kfar/trunk/kfar_arc/7z.inc new file mode 100644 index 0000000000..f4f1fc23f1 --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/7z.inc @@ -0,0 +1,3138 @@ +; Loading of 7z archives was ported from 7z sources (file 7zip\Archive\7z\7zIn.cpp). +; The version 7-Zip 4.42 was used. +; 7-Zip is copyright (C) 1999-2006 Igor Pavlov. +; Assembler version as KFar plugin has been written by diamond, 2007. + +virtual at 0 +file_in_7z: +.fullname dd ? ; pointer to cp866 string +.name dd ? +.namelen dd ? +.bIsDirectory db ? +.bPseudoFolder db ? + rb 2 +.parent dd ? ; pointer to parent directory record +.subfolders dd ? ; head of L2-list of subfolders [for folders] +.subfolders.end dd ? +.subfiles dd ? ; head of L2-list of files [for folders] +.subfiles.end dd ? +.NumSubItems dd ? +.next dd ? ; next item of list of subfolders or files +.prev dd ? ; previous item of list of subfolders or files +.attr dd ? +.FileCRC dd ? +.startPos dq ? +.CreationTime dq ? +.LastAccessTime dq ? +.LastWriteTime dq ? +.UnPackSize dq ? +.folder dd ? +.folder_index dd ? +.folderStart dq ? +.bAttrDefined db ? +.bStartPosDefined db ? +.bCRCDefined db ? +.bCreationTimeDefined db ? +.bLastAccessTimeDefined db ? +.bLastWriteTimeDefined db ? +.bHasStream db ? +.bAnti db ? +.stamp dd ? +.size = $ +end virtual + +virtual at 0 +handle_7z: +.type dd ? +.root.subfolders dd ? +.root.subfolders.end dd ? +.root.subfiles dd ? +.root.subfiles.end dd ? +.root.NumSubItems dd ? +.curdir dd ? +.NumFiles dd ? +.names_buf dd ? +.host dd ? +.host_datetime rd 6 +; streams info +.numPackStreams dd ? +.packSizes dd ? +.numFolders dd ? +.unpackCRCsDefined dd ? +.unpackCRCs dd ? +.folders dd ? +.last_folder dd ? +.last_pos dq ? +.last_context dd ? +.last_main_stream dd ? +.password_len dd ? ; -1 if no password defined; in characters +.password rw password_maxlen +.basesize = $ +; .size = .basesize + .NumFiles * file_in_7z.size +end virtual + +iglobal +align 4 +empty_7z_handle: + dd type_7z + dd 0,0,0,0,0,0 +endg + +kEnd = 0 +kHeader = 1 +kArchiveProperties = 2 +kAdditionalStreamsInfo = 3 +kMainStreamsInfo = 4 +kFilesInfo = 5 +kPackInfo = 6 +kUnPackInfo = 7 +kSubStreamsInfo = 8 +kSize = 9 +kCRC = 10 +kFolder = 11 +kCodersUnPackSize = 12 +kNumUnPackStream = 13 +kEmptyStream = 14 +kEmptyFile = 15 +kAnti = 16 +kName = 17 +kCreationTime = 18 +kLastAccessTime = 19 +kLastWriteTime = 20 +kWinAttributes = 21 +kComment = 22 +kEncodedHeader = 23 +kStartPos = 24 + +_7z.ReadByte: + cmp edi, [bufend] + jae return.err + mov al, [edi] + inc edi + ret +_7z.ReadWord: + add edi, 2 + cmp edi, [bufend] + ja return.err + mov ax, [edi-2] + ret +_7z.ReadDword: + add edi, 4 + cmp edi, [bufend] + ja return.err + mov eax, [edi-4] + ret + +_7z.SkipSize: + test edx, edx + jnz return.err + add edi, eax + jc return.err + cmp edi, [bufend] + ja return.err + ret + +_7z.ReadNumber: + xor eax, eax + push eax + push eax + call _7z.ReadByte + push ecx + xor ecx, ecx +@@: + add al, al + jnc @f + inc ecx + jmp @b +@@: + shr eax, cl + shr eax, 1 + jz @f + mov [esp+4+ecx], al +@@: + jecxz .ret + push edx + xor edx, edx +@@: + call _7z.ReadByte + mov [esp+8+edx], al + inc edx + loop @b + pop edx +.ret: + pop ecx + pop eax + pop edx + ret + +_7z.ReadNum: + push edx + call _7z.ReadNumber + test edx, edx + jnz return.err + test eax, eax + js return.err + pop edx + ret + +open_7z: +; CInArchive::ReadDatabase() + cmp byte [esi+6], 0 ; major version must be 0 + ; minor version does not be checked ([byte +7]=2 for now) + jz @f + xor eax, eax + ret +@@: + and [hOut], 0 + and [_7z.FreeSubStreams], 0 + and [_7z.tmpVector], 0 + push esi + add esi, 12 + mov ecx, 20 + call crc + pop esi + cmp eax, [esi+8] + jnz .header_crc_error + cmp dword [esi+24], 0 + jnz .header_error + mov edi, buffer + mov ecx, [esi+20] + mov [bufsize], ecx + test ecx, ecx + jnz .notempty + mov eax, empty_7z_handle + push ebp + call [close] + ret +.notempty: + cmp ecx, 1024 + jbe @f + call [pgalloc] + test eax, eax + jz .reterr + mov edi, eax +@@: + mov [bufptr], edi + lea eax, [edi+ecx] + mov [bufend], eax + mov eax, [esi+12] + mov edx, [esi+16] + add eax, 20h ; end of main header + adc edx, 0 + push edx + push eax + push 0 + push ebp + call [seek] + push ecx + push edi + push ebp + call [read] + cmp eax, ecx + jnz .header_error + push esi + mov esi, edi + call crc + pop esi + cmp eax, [esi+28] + jz .header_ok +.header_crc_error: +.header_error: + push ContinueBtn + push 1 + push HeaderError_ptr + push 1 + call [SayErr] +.clear: + mov ecx, [_7z.tmpVector] + jecxz @f + call [pgfree] +@@: + mov ecx, [hOut] + jecxz @f + call _7z.CloseHandle +@@: + mov ebx, [_7z.dataVectorSize] + test ebx, ebx + jz @f + call _7z.ReadAndDecodePackedStreams.free2 +@@: + mov ecx, [_7z.FreeSubStreams] + jecxz @f + call [pgfree] +@@: + mov ecx, [bufptr] + cmp ecx, buffer + jz .reterr + call [pgfree] +.reterr: + or eax, -1 + ret +.header_ok: + mov [_esp], esp + mov [inStream], ebp +.loop: + mov [error_proc], .header_error + mov [clear_proc], .clear + and [_7z.dataVectorSize], 0 + call _7z.ReadNum + cmp eax, kHeader + jz .found_header + cmp eax, kEncodedHeader + jnz .header_error + call _7z.ReadAndDecodePackedStreams + cmp [_7z.StreamsInfo.numFolders], 0 + jz .free_empty + cmp [_7z.StreamsInfo.numFolders], 1 + jnz return.err + mov ecx, [bufptr] + cmp ecx, buffer + jz @f + call [pgfree] +@@: + mov edi, [_7z.unpbuf+4] + mov [bufptr], edi + mov ecx, [_7z.unpbuf] + add ecx, edi + mov [bufend], ecx + mov [error_proc], .header_error + mov [clear_proc], .clear + and [_7z.dataVectorSize], 0 + call _7z.ReadNum + cmp eax, kHeader + jz .found_header + jmp return.err +.free_empty: + mov ecx, [bufptr] + cmp ecx, buffer + jz @f + call [pgfree] +@@: + push [inStream] + call [close] + mov eax, empty_7z_handle + ret +.found_header: + call _7z.ReadNum + cmp eax, kArchiveProperties + jnz .no_archive_props +@@: + call _7z.ReadNum + test eax, eax + jz @f + call _7z.SkipData + jmp @b +@@: + call _7z.ReadNum +.no_archive_props: + cmp eax, kAdditionalStreamsInfo + jnz .no_additional_streams + call _7z.ReadAndDecodePackedStreams + mov eax, [_7z.unpacked] + mov [_7z.dataVector], eax + mov eax, [_7z.StreamsInfo.numFolders] + mov [_7z.dataVectorSize], eax + mov [error_proc], .header_error + mov [clear_proc], .clear + call _7z.ReadNum +.no_additional_streams: + cmp eax, kMainStreamsInfo + jnz return.err + call _7z.ReadStreamsInfo + call _7z.ReadNum + test eax, eax + jnz .notempty2 +.empty2: + mov ebx, [_7z.dataVectorSize] + test ebx, ebx + jz @f + call _7z.ReadAndDecodePackedStreams.free2 +@@: + mov ecx, [_7z.FreeSubStreams] + jecxz @f + call [pgfree] +@@: + mov ecx, [bufptr] + cmp ecx, buffer + jz @f + call [pgfree] +@@: + push [inStream] + call [close] + mov eax, empty_7z_handle + ret +.notempty2: + cmp eax, kFilesInfo + jnz return.err + call _7z.ReadNum + test eax, eax + jz .empty2 + mov ebx, eax ; number of files in archive + imul ecx, ebx, file_in_7z.size + add ecx, handle_7z.basesize + mov [hOut.allocated], ecx + call [pgalloc] + test eax, eax + jz return.clear + mov [hOut], eax + mov [eax+handle_7z.type], type_7z + mov [eax+handle_7z.NumFiles], ebx + push edi + lea edi, [eax+handle_7z.numPackStreams] + mov esi, _7z.StreamsInfo + mov ecx, 6 + rep movsd + or [eax+handle_7z.password_len], -1 + or [eax+handle_7z.last_folder], -1 + mov [eax+handle_7z.last_context], ecx + mov [eax+handle_7z.names_buf], ecx + mov [eax+handle_7z.host], ecx + cmp [bPasswordDefined], cl + jz @f + mov ecx, [password_size] + mov [eax+handle_7z.password_len], ecx + lea edi, [eax+handle_7z.password] + mov esi, password_unicode + shr ecx, 1 + rep movsd + adc ecx, ecx + rep movsw +@@: + lea edi, [eax+handle_7z.basesize] + imul ecx, ebx, file_in_7z.size/4 + xor eax, eax + rep stosd + pop edi + mov eax, [_7z.StreamsInfo.SubStreamsSizes] + mov [_7z.FreeSubStreams], eax + mov [error_proc], .header_error + mov [clear_proc], .clear + mov ecx, ebx + shl ecx, 2 + call [pgalloc] + test eax, eax + jz return.clear + push edi + mov edi, eax + mov [_7z.tmpVector], eax + add eax, ebx + mov [_7z.emptyStreams], eax + add eax, ebx + mov [_7z.emptyFiles], eax + add eax, ebx + mov [_7z.antiFiles], eax + mov ecx, ebx + xor eax, eax + rep stosd + pop edi + mov [_7z.numEmptyStreams], eax +.parse_header: + call _7z.ReadNum + test eax, eax + jz .parse_header_done + mov ecx, eax ; ecx = type + call _7z.ReadNum ; eax = size + cmp ecx, kName + jz .parse_names + cmp ecx, kWinAttributes + jz .parse_winAttr + cmp ecx, kStartPos + jz .parse_startPos + cmp ecx, kEmptyStream + jz .parse_emptyStream + cmp ecx, kEmptyFile + jz .parse_emptyFile + cmp ecx, kAnti + jz .parse_anti + cmp ecx, kCreationTime + jz .parse_time + cmp ecx, kLastWriteTime + jz .parse_time + cmp ecx, kLastAccessTime + jz .parse_time + xor edx, edx + call _7z.SkipSize + jmp .parse_header +.parse_names: + push eax + call _7z.SwitchStream + pop eax + jz @f + mov eax, [bufend] + sub eax, edi +@@: + shr eax, 1 ; size of ANSI string is a half of size of UNICODE string + mov ecx, eax + call [pgalloc] + test eax, eax + jz return.clear + mov ebp, eax + mov esi, [hOut] + mov [esi+handle_7z.names_buf], eax + add eax, ecx + push eax ; remember limit + mov ecx, ebx + add esi, handle_7z.basesize + file_in_7z.fullname + mov [bWasWarning], 0 +.parse_names_loop: + mov [esi], ebp + add esi, file_in_7z.size +.parse_names_loop_int: + cmp ebp, [esp] + jae return.err + call _7z.ReadWord +; UNICODE char -> cp866 char + cmp ax, 0x80 + jb .id + cmp ax, 0x401 + jz .yo1 + cmp ax, 0x451 + jz .yo2 + cmp ax, 0x410 + jb .unk + cmp ax, 0x440 + jb .rus1 + cmp ax, 0x450 + jb .rus2 +.unk: + cmp [bWasWarning], 0 + jnz @f + push ContinueBtn + push 1 + push aEncodingProblem_str_ptr + push 3 + push aEncodingProblem + call [Message] + inc [bWasWarning] +@@: + mov al, '_' + jmp .id +.yo1: + mov al, 'Ё' + jmp .id +.yo2: + mov al, 'ё' + jmp .id +.rus1: +; 0x410-0x43F -> 0x80-0xAF + add al, 0x70 + jmp .id +.rus2: +; 0x440-0x44F -> 0xE0-0xEF + add al, 0xA0 +.id: + mov [ebp], al + inc ebp + test al, al + jnz .parse_names_loop_int + loop .parse_names_loop + pop eax + call _7z.UnswitchStream + jmp .parse_header +.parse_winAttr: + mov edx, [_7z.tmpVector] + push ebx + mov ecx, ebx + mov ebx, edx + call _7z.ReadBoolVector2 + pop ebx + call _7z.SwitchStream + mov esi, [hOut] + add esi, handle_7z.basesize + mov ecx, ebx +.winAttrLoop: + mov al, [edx] + inc edx + mov [esi+file_in_7z.bAttrDefined], al + test al, al + jz @f + call _7z.ReadDword + mov [esi+file_in_7z.attr], eax +@@: + add esi, file_in_7z.size + loop .winAttrLoop + call _7z.UnswitchStream + jmp .parse_header +.parse_startPos: + mov edx, [_7z.tmpVector] + push ebx + mov ecx, ebx + mov ebx, edx + call _7z.ReadBoolVector2 + pop ebx + call _7z.SwitchStream + mov esi, [hOut] + add esi, handle_7z.basesize + mov ecx, ebx +.startPosLoop: + mov al, [edx] + inc edx + mov [esi+file_in_7z.bStartPosDefined], al + test al, al + jz @f + call _7z.ReadDword + mov dword [esi+file_in_7z.startPos], eax + call _7z.ReadDword + mov dword [esi+file_in_7z.startPos+4], eax +@@: + add esi, file_in_7z.size + loop .startPosLoop + call _7z.UnswitchStream + jmp .parse_header +.parse_emptyStream: + mov edx, [_7z.emptyStreams] + push ebx + mov ecx, ebx + mov ebx, edx + call _7z.ReadBoolVector + pop ebx + and [_7z.numEmptyStreams], 0 + mov ecx, ebx +.emptyStrLoop: + cmp byte [edx], 0 + jz @f + inc [_7z.numEmptyStreams] +@@: + inc edx + loop .emptyStrLoop + jmp .parse_header +.parse_emptyFile: + push ebx + mov ecx, [_7z.numEmptyStreams] + mov ebx, [_7z.emptyFiles] + call _7z.ReadBoolVector + pop ebx + jmp .parse_header +.parse_anti: + push ebx + mov ecx, [_7z.numEmptyStreams] + mov ebx, [_7z.antiFiles] + call _7z.ReadBoolVector + pop ebx + jmp .parse_header +.parse_time: + push ecx + push ebx + mov ecx, ebx + mov ebx, [_7z.tmpVector] + call _7z.ReadBoolVector2 + pop ebx + call _7z.SwitchStream + mov esi, [hOut] + add esi, handle_7z.basesize + xor ecx, ecx +.timeLoop: + mov eax, [_7z.tmpVector] + mov al, [eax+ecx] + pop edx + push edx + mov [esi + file_in_7z.bCreationTimeDefined + edx - kCreationTime], al + test al, al + jz @f + call _7z.ReadDword + push eax + call _7z.ReadDword + mov edx, eax + pop eax + push edi + mov edi, [esp+4] + lea edi, [esi + file_in_7z.CreationTime + (edi-kCreationTime)*8] + call ntfs_datetime_to_bdfe + pop edi +@@: + add esi, file_in_7z.size + inc ecx + cmp ecx, ebx + jb .timeLoop + call _7z.UnswitchStream + pop eax + jmp .parse_header +.parse_header_done: + xor ecx, ecx ; index in emptyFiles + xor edx, edx ; index in subStreams + xor ebp, ebp ; index in files + mov esi, [hOut] + add esi, handle_7z.basesize +.filesLoop: + mov eax, [_7z.emptyStreams] + mov al, [eax+ebp] + xor al, 1 + mov [esi+file_in_7z.bHasStream], al + jz .nostream + mov [esi+file_in_7z.bIsDirectory], 0 + mov [esi+file_in_7z.bAnti], 0 + mov eax, [_7z.StreamsInfo.SubStreamsSizes] + push dword [eax+edx*8] + pop dword [esi+file_in_7z.UnPackSize] + push dword [eax+edx*8+4] + pop dword [esi+file_in_7z.UnPackSize+4] + mov eax, [_7z.StreamsInfo.SubStreamsCRCsDefined] + mov al, [eax+edx] + mov [esi+file_in_7z.bCRCDefined], al + test al, al + jz @f + mov eax, [_7z.StreamsInfo.SubStreamsCRCs] + mov eax, [eax+edx*4] + mov [esi+file_in_7z.FileCRC], eax +@@: + inc edx + jmp .filesCont +.nostream: + mov eax, [_7z.emptyFiles] + cmp byte [eax+ecx], 0 + setz [esi+file_in_7z.bIsDirectory] + mov eax, [_7z.antiFiles] + cmp byte [eax+ecx], 0 + setnz [esi+file_in_7z.bAnti] + and dword [esi+file_in_7z.UnPackSize], 0 + and dword [esi+file_in_7z.UnPackSize+4], 0 + mov [esi+file_in_7z.bCRCDefined], 0 + inc ecx +.filesCont: + inc ebp + add esi, file_in_7z.size + dec ebx + jnz .filesLoop + mov ecx, [_7z.tmpVector] + call [pgfree] + and [_7z.tmpVector], 0 + mov ebx, [_7z.dataVectorSize] + test ebx, ebx + jz @f + call _7z.ReadAndDecodePackedStreams.free2 + and [_7z.dataVectorSize], 0 +@@: + mov ecx, [_7z.FreeSubStreams] + jecxz @f + call [pgfree] + and [_7z.FreeSubStreams], 0 +@@: + mov ecx, [bufptr] + cmp ecx, buffer + jz @f + call [pgfree] + mov [bufptr], buffer +@@: + xor esi, esi ; index of folder + mov edi, [hOut] + mov ebx, [edi+handle_7z.NumFiles] + add edi, handle_7z.basesize ; pointer to fileinfo + push 0 ; start index of packed stream for folder +.getfoldersloop0: + xor edx, edx ; index in folder + push edx edx ; position in folder +.getfoldersloop: + dec ebx + js .getfoldersdone + cmp [edi+file_in_7z.bHasStream], 0 + jnz @f + test edx, edx + jz .nofolder +@@: + test edx, edx + jnz .notfirst +; skip empty folders +@@: + mov eax, [hOut] + cmp esi, [eax+handle_7z.numFolders] + jae return.err + mov eax, [eax+handle_7z.folders] + mov eax, [eax+esi*4] + cmp edx, [eax+_7z.StreamsInfo.numUnPackStreams] + jb @f + inc esi + jmp @b +@@: +.notfirst: + mov [edi+file_in_7z.folder], esi + mov [edi+file_in_7z.folder_index], edx + mov eax, [esp] + mov dword [edi+file_in_7z.folderStart], eax + mov eax, [esp+4] + mov dword [edi+file_in_7z.folderStart+4], eax + mov ecx, dword [edi+file_in_7z.UnPackSize] + add [esp], ecx + mov ecx, dword [edi+file_in_7z.UnPackSize+4] + adc [esp+4], ecx + add edi, file_in_7z.size + inc edx + mov eax, [hOut] + mov eax, [eax+handle_7z.folders] + mov eax, [eax+esi*4] + cmp edx, [eax+_7z.StreamsInfo.numUnPackStreams] + jb .getfoldersloop + inc esi + pop edx edx + jmp .getfoldersloop0 +.nofolder: + push -1 + pop eax + mov [edi+file_in_7z.folder], eax + mov [edi+file_in_7z.folder_index], eax + mov dword [edi+file_in_7z.folderStart], eax + mov dword [edi+file_in_7z.folderStart+4], eax + add edi, file_in_7z.size + jmp .getfoldersloop +.getfoldersdone: + pop eax eax eax + mov ebp, [hOut] + mov esi, [ebp+handle_7z.folders] + xor ebx, ebx + cmp ebx, [ebp+handle_7z.numFolders] + jae .getoffsdone +.getoffsloop: + lodsd + test ebx, ebx + jnz .getoffs2 + mov edx, dword [_7z.StreamsInfo.dataOffset] + mov dword [eax+_7z.StreamsInfo.packOffset], edx + mov edx, dword [_7z.StreamsInfo.dataOffset+4] + mov dword [eax+_7z.StreamsInfo.packOffset+4], edx + jmp .getoffscont +.getoffs2: + mov ecx, [esi-8] + mov edx, dword [ecx+_7z.StreamsInfo.packOffset] + mov dword [eax+_7z.StreamsInfo.packOffset], edx + mov edx, dword [ecx+_7z.StreamsInfo.packOffset+4] + mov dword [eax+_7z.StreamsInfo.packOffset+4], edx + mov edi, [ecx+_7z.StreamsInfo.startPackedStream] + mov ecx, [ecx+_7z.StreamsInfo.numPackedStreams] + push ecx + add ecx, edi + cmp ecx, [ebp+handle_7z.numPackStreams] + ja return.err + pop ecx + shl edi, 3 + add edi, [ebp+handle_7z.packSizes] +@@: + dec ecx + js @f + mov edx, [edi] + add dword [eax+_7z.StreamsInfo.packOffset], edx + mov edx, [edi+4] + adc dword [eax+_7z.StreamsInfo.packOffset+4], edx + add edi, 8 + jmp @b +@@: +.getoffscont: + inc ebx + cmp ebx, [ebp+handle_7z.numFolders] + jb .getoffsloop +.getoffsdone: + mov edx, [hOut] + mov ebx, [edx+handle_7z.NumFiles] + lea edi, [edx+handle_7z.root.subfolders] + add edx, handle_7z.basesize + push file_in_7z.size + call init_file_links + mov eax, [hOut] + and [eax+handle_7z.curdir], 0 ; set root directory + mov esi, [inStream] + mov [eax+handle_7z.host], esi + lea edi, [eax+handle_7z.host_datetime] + mov esi, [esp+16] + add esi, 8 + mov ecx, 6 + rep movsd + ret + +_7z.CloseHandle: + mov esi, ecx + push [esi+handle_7z.host] + call [close] + mov ecx, [esi+handle_7z.packSizes] + call [pgfree] + mov ecx, [esi+handle_7z.folders] + call [pgfree] + mov ecx, [esi+handle_7z.names_buf] + call [pgfree] + mov ecx, [esi+handle_7z.last_context] + jecxz @f + call [pgfree] +@@: + mov ecx, esi + call [pgfree] + ret + +close_7z: + mov ecx, [esp+4] + cmp ecx, empty_7z_handle + jz @f + call _7z.CloseHandle +@@: + ret 4 + +uglobal +align 4 +_7z.unpacked dd ? +_7z.unpbuf rd 2*8 +_7z.CurInStream dd ? +_7z.dataVector dd ? +_7z.dataVectorSize dd ? +_7z.FreeSubStreams dd ? +_7z.tmpVector dd ? +_7z.emptyStreams dd ? +_7z.numEmptyStreams dd ? +_7z.emptyFiles dd ? +_7z.antiFiles dd ? +endg + +_7z.ReadAndDecodePackedStreams: + call _7z.ReadStreamsInfo + mov ecx, [_7z.StreamsInfo.numFolders] + test ecx, ecx + jz .ret2 + push ecx + mov ecx, [_7z.StreamsInfo.SubStreamsSizes] + jecxz @f + call [pgfree] + and [_7z.StreamsInfo.SubStreamsSizes], 0 +@@: + pop ecx + mov eax, _7z.unpbuf + cmp ecx, 8 + jbe .1 + shl ecx, 3 + call [pgalloc] + test eax, eax + jz return.clear + mov esi, eax +@@: + and dword [esi], 0 + add esi, 4 + sub ecx, 4 + jnz @b +.1: + mov [_7z.unpacked], eax + mov esi, eax + xor ecx, ecx + mov [_7z.CurInStream], ecx + mov [error_proc], .error + mov [clear_proc], .clear +.loop: + mov eax, [_7z.StreamsInfo.folders] + mov ebx, [eax+ecx*4] + call _7z.GetUnPackSize + test edx, edx + jnz return.err + test eax, eax + js return.err + push ecx + mov [esi], eax + mov [_7z.decode.outBufferSize], eax + mov ecx, eax + call [pgalloc] + test eax, eax + jz return.err + mov [esi+4], eax + mov [_7z.decode.outBufferPtr], eax + push esi + call _7z.decode + pop esi + pop ecx + push ecx + mov eax, [_7z.StreamsInfo.unpackCRCsDefined] + cmp byte [eax+ecx], 0 + jz @f + push esi + mov ecx, [esi] + mov esi, [esi+4] + call crc + pop esi + pop ecx + push ecx + mov edx, [_7z.StreamsInfo.unpackCRCs] + cmp [edx+ecx*4], eax + jnz return.err +@@: + add esi, 8 + pop ecx + inc ecx + cmp ecx, [_7z.StreamsInfo.numFolders] + jb .loop +.ret: + mov ecx, [_7z.StreamsInfo.folders] + call [pgfree] + mov [error_proc], .error2 + mov [clear_proc], .clear2 +.ret2: + mov ecx, [_7z.StreamsInfo.packSizes] + call [pgfree] + ret + +.error: + call .free + jmp _7z.ReadStreamsInfo.error +.clear: + call .free + jmp _7z.ReadStreamsInfo.clear +.error2: + call .free + jmp open_7z.header_error +.clear2: + call .free + jmp open_7z.clear +.free: + mov ebx, [_7z.StreamsInfo.numFolders] +.free2: + dec ebx + js @f + mov ecx, [_7z.unpacked] + mov ecx, [ecx+ebx*8+4] + call [pgfree] + jmp .free2 +@@: + mov ecx, [_7z.unpacked] + cmp ecx, _7z.unpbuf + jz @f + call [pgfree] +@@: + ret + +_7z.GetUnPackSize: + xor edx, edx + mov eax, [ebx+_7z.StreamsInfo.numOutStreams] + test eax, eax + jz .ret +.scan: + dec eax + js return.err + push ecx + mov ecx, [ebx+_7z.StreamsInfo.numBindPairs] + mov edx, [ebx+_7z.StreamsInfo.bindPairs] +@@: + add edx, 8 + dec ecx + js .found + cmp [edx-4], eax + jnz @b + pop ecx + jmp .scan +.found: + mov [ebx+_7z.StreamsInfo.mainOutStream], eax + mov ecx, [ebx+_7z.StreamsInfo.unpackSizes] + mov edx, [ecx+eax*8+4] + mov eax, [ecx+eax*8] + pop ecx +.ret: + ret + +uglobal +align 4 +_7z.StreamsInfo: +.numPackStreams dd ? +.packSizes dd ? ; 8 bytes per item +.numFolders dd ? +.unpackCRCsDefined dd ? +.unpackCRCs dd ? +.folders dd ? +.folders.size dd ? +.folders.alloc dd ? +.dataOffset dq ? +.packCRCsDefined dd ? ; 1 byte per item +.packCRCs dd ? ; 4 bytes per item +virtual at 0 +.numCoders dd ? +.bindPairs dd ? +.numBindPairs dd ? +.packedStreams dd ? +.numPackedStreams dd ? +.startPackedStream dd ? +.numOutStreams dd ? +.unpackSizes dd ? +.mainOutStream dd ? +.numUnPackStreams dd ? +.packOffset dq ? +.fsz = $ +end virtual +.numSubStreams dd ? +.SubStreamsSizes dd ? +.SubStreamsCRCsDefined dd ? +.SubStreamsCRCs dd ? +.tmpSubStreamsCRCsDefined dd ? +.tmpSubStreamsCRCs dd ? +endg + +_7z.SkipData: + call _7z.ReadNumber + call _7z.SkipSize + ret + +_7z.WaitAttribute: + call _7z.ReadNumber + cmp eax, ecx + jz @f + test eax, eax + jz return.err + call _7z.SkipData + jmp _7z.WaitAttribute +@@: + ret + +_7z.ReadBoolVector2: +; in: ebx->vector, ecx=size + call _7z.ReadByte + test al, al + jz _7z.ReadBoolVector + push ebx ecx + jecxz .ret +@@: + mov byte [ebx], 1 + inc ebx + loop @b +.ret: + pop ecx ebx + ret + +_7z.ReadBoolVector: + push ebx ecx + jecxz .ret + xor eax, eax +.1: + add al, al + jnz @f + call _7z.ReadByte + stc + adc al, al +@@: + setc byte [ebx] + inc ebx + loop .1 +.ret: + pop ecx ebx + ret + +_7z.ReadHashDigests: +; in: ebx->bool vector, esi->crc, ecx=size + call _7z.ReadBoolVector2 + jecxz .ret +.1: + xor eax, eax + cmp byte [ebx], al + jz @f + call _7z.ReadDword +@@: + mov [esi], eax + add esi, 4 + inc ebx + loop .1 +.ret: + ret + +uglobal +_7z.saved_edi dd ? +_7z.saved_edi_end dd ? +endg + +_7z.SwitchStream: + mov eax, [bufend] + mov [_7z.saved_edi_end], eax + call _7z.ReadByte + test al, al + jnz @f + ret +@@: + call _7z.ReadNum + mov [_7z.saved_edi], edi + cmp eax, [_7z.dataVectorSize] + jae return.err + shl eax, 3 + add eax, [_7z.dataVector] + mov edi, [eax+4] + mov eax, [eax] + add eax, edi + mov [bufend], eax + ret + +_7z.UnswitchStream: + mov eax, [_7z.saved_edi_end] + cmp eax, [bufend] + jnz @f + ret +@@: + mov [bufend], eax + mov edi, [_7z.saved_edi] +@@: + ret + +; 6 программистов пытались код понять, +; Один из них сошёл с ума, и их осталось 5. + +_7z.ReadStreamsInfo: + xor eax, eax + mov [_7z.StreamsInfo.numPackStreams], eax + mov [_7z.StreamsInfo.packSizes], eax + mov [_7z.StreamsInfo.numFolders], eax + mov [_7z.StreamsInfo.folders], eax + mov [_7z.StreamsInfo.numSubStreams], eax + mov [_7z.StreamsInfo.SubStreamsSizes], eax + mov [_7z.StreamsInfo.tmpSubStreamsCRCsDefined], eax + mov [error_proc], .error + mov [clear_proc], .clear +.mainloop: + call _7z.ReadNum + test eax, eax + jz @b + cmp eax, kSubStreamsInfo + jz .SubStreamsInfo + cmp eax, kUnPackInfo + jz .UnpackInfo + cmp eax, kPackInfo + jnz return.err + +.PackInfo: + cmp [_7z.StreamsInfo.numPackStreams], 0 + jnz return.err + call _7z.ReadNumber + add eax, 0x20 + adc edx, 0 + mov dword [_7z.StreamsInfo.dataOffset], eax + mov dword [_7z.StreamsInfo.dataOffset+4], edx + call _7z.ReadNum + mov [_7z.StreamsInfo.numPackStreams], eax + mov ecx, kSize + call _7z.WaitAttribute + mov ecx, [_7z.StreamsInfo.numPackStreams] + imul ecx, 8+1+4 + jecxz .nostreams1 + call [pgalloc] + test eax, eax + jz return.clear + mov [_7z.StreamsInfo.packSizes], eax + mov ecx, [_7z.StreamsInfo.numPackStreams] + push eax + lea eax, [eax+ecx*8] + mov [_7z.StreamsInfo.packCRCsDefined], eax + mov ebx, eax + add eax, ecx + mov [_7z.StreamsInfo.packCRCs], eax +@@: + mov byte [ebx], 0 + inc ebx + loop @b + pop eax +.nostreams1: + mov ecx, [_7z.StreamsInfo.numPackStreams] + jecxz .noloop1 + mov esi, eax +@@: + call _7z.ReadNumber + mov [esi], eax + mov [esi+4], edx + add esi, 8 + loop @b +.noloop1: + call _7z.ReadNum + test eax, eax + jz .mainloop + cmp eax, kCRC + jz .packInfo.crc + call _7z.SkipData + jmp .noloop1 +.packInfo.crc: + mov esi, [_7z.StreamsInfo.packCRCs] + mov ebx, [_7z.StreamsInfo.packCRCsDefined] + mov ecx, [_7z.StreamsInfo.numPackStreams] + call _7z.ReadHashDigests + jmp .noloop1 + +.UnpackInfo: + cmp [_7z.StreamsInfo.folders], 0 + jnz return.err + mov ecx, kFolder + call _7z.WaitAttribute + call _7z.ReadNum + mov ecx, eax + mov [_7z.StreamsInfo.numFolders], eax + call _7z.SwitchStream + test ecx, ecx + jz .nofolders + push ecx + mov ecx, 0x1000 + and [_7z.StreamsInfo.folders.size], 0 + mov [_7z.StreamsInfo.folders.alloc], ecx + call [pgalloc] + test eax, eax + jz return.clear + mov [_7z.StreamsInfo.folders], eax + pop ecx + lea ecx, [ecx*9] + call .folders_alloc + xor ecx, ecx +.folderloop: + mov eax, [_7z.StreamsInfo.folders] + push [_7z.StreamsInfo.folders.size] + pop dword [eax+ecx*4] + push ebp + mov [_ebp], ebp + push ecx + mov ecx, _7z.StreamsInfo.fsz + call .folders_alloc + mov ebp, eax + add ebp, [_7z.StreamsInfo.folders] + call _7z.ReadNum + mov [ebp+_7z.StreamsInfo.numCoders], eax + test eax, eax + jz return.err + mov ecx, eax + push ecx + shl ecx, 2 + sub ebp, [_7z.StreamsInfo.folders] + call .folders_alloc + add ebp, [_7z.StreamsInfo.folders] + pop ecx + add eax, [_7z.StreamsInfo.folders] +@@: + and dword [eax], 0 + add eax, 4 + loop @b + push 0 ; numOutStreams + push 0 ; numInStreams +; [folders] = array of pointers to coders info +; Format of coder info: +; dd NextCoder +; db MethodID.IDSize +; times IDSize db MethodID.ID +; dd NumInStreams +; dd NumOutStreams +; dd PropSize +; times PropSize db Properties + xor esi, esi +.coders_loop: + call _7z.ReadByte + mov dl, al + and eax, 0xF + lea ecx, [eax+17] + sub ebp, [_7z.StreamsInfo.folders] + call .folders_alloc + add ebp, [_7z.StreamsInfo.folders] + push eax + mov ecx, [_7z.StreamsInfo.folders] + lea ebx, [ebp+esi*4+_7z.StreamsInfo.fsz] +@@: + cmp dword [ebx], 0 + jz @f + mov ebx, [ebx] + add ebx, ecx + jmp @b +@@: + mov [ebx], eax + pop ebx + add ebx, ecx + and dword [ebx], 0 + add ebx, 4 + mov ecx, edx + and ecx, 0xF + mov byte [ebx], cl + inc ebx + jecxz .2 +@@: + call _7z.ReadByte + mov byte [ebx], al + inc ebx + loop @b +.2: + test dl, 10h + jnz .coder_multiple_streams + mov dword [ebx], 1 + mov dword [ebx+4], 1 + inc dword [esp] + inc dword [esp+4] + jmp @f +.coder_multiple_streams: + call _7z.ReadNum + mov [ebx], eax + add dword [esp], eax + call _7z.ReadNum + mov [ebx+4], eax + add dword [esp+4], eax +; all currently defined 7z coders have 1 unpacked stream +; moreover, all reasonable coders have 1 unpacked stream +; so assume 1 output stream for unpacker - this simplifies decoding procedure + cmp eax, 1 + jnz return.err +@@: + and dword [ebx+8], 0 + add ebx, 12 + test dl, 20h + jz .coder_no_properties + call _7z.ReadNum + test eax, eax + jz .coder_no_properties + mov [ebx-4], eax + mov ecx, eax + sub ebx, [_7z.StreamsInfo.folders] + sub ebp, [_7z.StreamsInfo.folders] + call .folders_alloc + add ebp, [_7z.StreamsInfo.folders] + add ebx, [_7z.StreamsInfo.folders] +@@: + call _7z.ReadByte + mov [ebx], al + inc ebx + loop @b +.coder_no_properties: + test dl, dl + js .coders_loop + inc esi + cmp esi, [ebp+_7z.StreamsInfo.numCoders] + jb .coders_loop + mov [ebp+_7z.StreamsInfo.numUnPackStreams], 1 + mov eax, [esp+4] + dec eax + js return.err + mov [ebp+_7z.StreamsInfo.numBindPairs], eax + push eax + mov ecx, eax + shl ecx, 3 + sub ebp, [_7z.StreamsInfo.folders] + call .folders_alloc + add ebp, [_7z.StreamsInfo.folders] + mov [ebp+_7z.StreamsInfo.bindPairs], eax + pop ecx + jecxz .noloop3 + mov esi, eax + add esi, [_7z.StreamsInfo.folders] +@@: + call _7z.ReadNum + mov [esi], eax + cmp eax, [esp] + jae return.err + call _7z.ReadNum + mov [esi+4], eax + cmp eax, [esp+4] + jae return.err + add esi, 8 + loop @b +.noloop3: + pop eax ; numInStreams + pop edx ; numOutStreams + mov [ebp+_7z.StreamsInfo.numOutStreams], edx + sub eax, edx + js return.err + inc eax + mov [ebp+_7z.StreamsInfo.numPackedStreams], eax + mov ecx, eax + push eax + shl ecx, 2 + sub ebp, [_7z.StreamsInfo.folders] + call .folders_alloc + add ebp, [_7z.StreamsInfo.folders] + mov [ebp+_7z.StreamsInfo.packedStreams], eax + pop ecx + mov esi, eax + add esi, [_7z.StreamsInfo.folders] + cmp ecx, 1 + jnz .multiplePackedStreams + mov ebx, [ebp+_7z.StreamsInfo.bindPairs] + add ebx, [_7z.StreamsInfo.folders] + push edx + xor ecx, ecx +.3: + push ebx + mov edx, [ebp+_7z.StreamsInfo.numBindPairs] +@@: + dec edx + js .5 + cmp dword [ebx], ecx + jz .4 + add ebx, 8 + jmp @b +.4: + pop ebx + inc ecx + jmp .3 +.5: + pop ebx + pop edx + mov [esi], ecx + jmp .commonPackedStreams +.multiplePackedStreams: + call _7z.ReadNum + mov [esi], eax + add esi, 4 + loop .multiplePackedStreams +.commonPackedStreams: + mov ecx, edx + shl ecx, 3 + sub ebp, [_7z.StreamsInfo.folders] + call .folders_alloc + add ebp, [_7z.StreamsInfo.folders] + mov [ebp+_7z.StreamsInfo.unpackSizes], eax + pop ecx + xor edx, edx + jecxz @f + mov eax, [_7z.StreamsInfo.folders] + mov eax, [eax+(ecx-1)*4] + add eax, [_7z.StreamsInfo.folders] + mov edx, [eax+_7z.StreamsInfo.numPackedStreams] + add edx, [eax+_7z.StreamsInfo.startPackedStream] +@@: + mov [ebp+_7z.StreamsInfo.startPackedStream], edx + pop ebp + inc ecx + cmp ecx, [_7z.StreamsInfo.numFolders] + jb .folderloop +.nofolders: + call _7z.UnswitchStream + mov ecx, kCodersUnPackSize + call _7z.WaitAttribute + xor ecx, ecx +.6: + cmp ecx, [_7z.StreamsInfo.numFolders] + jae .7 + mov eax, [_7z.StreamsInfo.folders] + push ebp + mov ebp, [eax+ecx*4] + add ebp, eax + mov esi, [ebp+_7z.StreamsInfo.numOutStreams] + mov ebp, [ebp+_7z.StreamsInfo.unpackSizes] + add ebp, [_7z.StreamsInfo.folders] +@@: + call _7z.ReadNumber + mov dword [ebp], eax + mov dword [ebp+4], edx + add ebp, 8 + dec esi + jnz @b + pop ebp + inc ecx + jmp .6 +.7: +; convert all relative addresses to pointers + xor ecx, ecx + mov edx, [_7z.StreamsInfo.folders] +.8: + cmp ecx, [_7z.StreamsInfo.numFolders] + jae .9 + lea eax, [edx+ecx*4] + add [eax], edx + mov eax, [eax] + add [eax+_7z.StreamsInfo.bindPairs], edx + add [eax+_7z.StreamsInfo.packedStreams], edx + add [eax+_7z.StreamsInfo.unpackSizes], edx + mov ebx, [eax+_7z.StreamsInfo.numCoders] + add eax, _7z.StreamsInfo.fsz + inc ecx +.11: + dec ebx + js .8 + push eax +@@: + cmp dword [eax], 0 + jz @f + add [eax], edx + mov eax, [eax] + jmp @b +@@: + pop eax + add eax, 4 + jmp .11 +.9: +; done + mov eax, [_7z.StreamsInfo.numFolders] + lea edx, [edx+eax*4] + mov [_7z.StreamsInfo.unpackCRCsDefined], edx + add edx, eax + mov [_7z.StreamsInfo.unpackCRCs], edx +@@: + call _7z.ReadNum + test eax, eax + jz .mainloop + cmp eax, kCRC + jz .unpackInfo.crc + call _7z.SkipData + jmp @b +.unpackInfo.crc: + mov esi, [_7z.StreamsInfo.unpackCRCs] + mov ebx, [_7z.StreamsInfo.unpackCRCsDefined] + mov ecx, [_7z.StreamsInfo.numFolders] + call _7z.ReadHashDigests + jmp @b + +.SubStreamsInfo: + cmp [_7z.StreamsInfo.numFolders], 0 + jz return.err + cmp [_7z.StreamsInfo.numSubStreams], 0 + jnz return.err + mov ebx, [_7z.StreamsInfo.folders] +.ssloop1: + call _7z.ReadNum + cmp eax, kNumUnPackStream + jz .NumUnPackStream + cmp eax, kCRC + jz .break1 + cmp eax, kSize + jz .break1 + test eax, eax + jz .break1 + call _7z.SkipData + jmp .ssloop1 +.NumUnPackStream: + xor ecx, ecx +@@: + call _7z.ReadNum + mov edx, [ebx+ecx*4] + mov [edx+_7z.StreamsInfo.numUnPackStreams], eax + inc ecx + cmp ecx, [_7z.StreamsInfo.numFolders] + jb @b + jmp .ssloop1 +.break1: +; calculate number of substreams and number of defined digests + xor ecx, ecx + xor ebp, ebp + push 0 + push eax + xor eax, eax +.ssloop2: + mov edx, [ebx+ecx*4] + mov edx, [edx+_7z.StreamsInfo.numUnPackStreams] + cmp edx, 1 + jz @f + inc ebp +@@: + add eax, edx + jc return.err + cmp edx, 1 + jnz @f + push eax + mov eax, [_7z.StreamsInfo.unpackCRCsDefined] + cmp byte [eax+ecx], 0 + pop eax + jz @f + xor edx, edx +@@: + add [esp+4], edx + inc ecx + cmp ecx, [_7z.StreamsInfo.numFolders] + jb .ssloop2 + mov [_7z.StreamsInfo.numSubStreams], eax + imul ecx, eax, 4+8+1 + jecxz .noss1 + push eax + call [pgalloc] + pop ecx + test eax, eax + jz return.clear + mov [_7z.StreamsInfo.SubStreamsSizes], eax + lea eax, [eax+ecx*8] + mov [_7z.StreamsInfo.SubStreamsCRCsDefined], eax + add eax, ecx + mov [_7z.StreamsInfo.SubStreamsCRCs], eax +@@: + dec eax + mov byte [eax], 0 + loop @b +.noss1: + mov ecx, [esp+4] + jecxz @f + imul ecx, 4+1 + call [pgalloc] + test eax, eax + jz return.clear + mov [_7z.StreamsInfo.tmpSubStreamsCRCsDefined], eax + add eax, [esp+4] + mov [_7z.StreamsInfo.tmpSubStreamsCRCs], eax +@@: + test ebp, ebp + jz @f + cmp dword [esp], kSize + jnz return.err +@@: + xor ecx, ecx + mov ebp, [_7z.StreamsInfo.SubStreamsSizes] +.ssloop3: + mov ebx, [_7z.StreamsInfo.folders] + mov ebx, [ebx+ecx*4] + mov eax, [ebx+_7z.StreamsInfo.numUnPackStreams] + dec eax + js .sscont3 + push 0 + push 0 +@@: + dec eax + js @f + push eax + call _7z.ReadNumber + mov [ebp], eax + mov [ebp+4], edx + add ebp, 8 + add [esp+4], eax + adc [esp+8], edx + jc return.err + pop eax + jmp @b +@@: + call _7z.GetUnPackSize + sub eax, [esp] + sbb edx, [esp+4] + jc return.err + mov [ebp], eax + mov [ebp+4], edx + add ebp, 8 + add esp, 8 +.sscont3: + inc ecx + cmp ecx, [_7z.StreamsInfo.numFolders] + jb .ssloop3 + pop eax + cmp eax, kSize + jnz @f + call _7z.ReadNum +@@: + cmp eax, kCRC + jz .sscrc + test eax, eax + jz .ssend + call _7z.SkipData +.ssloop4: + call _7z.ReadNum + jmp @b +.sscrc: + pop ecx + push ecx + mov ebx, [_7z.StreamsInfo.tmpSubStreamsCRCsDefined] + mov esi, [_7z.StreamsInfo.tmpSubStreamsCRCs] + call _7z.ReadHashDigests + xor ecx, ecx ; index in out + xor edx, edx ; index in tmp + push -1 + pop ebx ; index in folders +.ssloop5: + inc ebx + cmp ebx, [_7z.StreamsInfo.numFolders] + jae .ssloop4 + mov eax, [_7z.StreamsInfo.folders] + mov ebp, [eax+ebx*4] + mov ebp, [ebp+_7z.StreamsInfo.numUnPackStreams] + cmp ebp, 1 + jnz @f + mov eax, [_7z.StreamsInfo.unpackCRCsDefined] + cmp byte [eax+ebx], 0 + jz @f + mov esi, [_7z.StreamsInfo.SubStreamsCRCsDefined] + mov byte [esi+ecx], 1 + mov esi, [_7z.StreamsInfo.unpackCRCs] + mov eax, [esi+ebx*4] + mov esi, [_7z.StreamsInfo.SubStreamsCRCs] + mov [esi+ecx*4], eax + inc ecx + jmp .ssloop5 +@@: + dec ebp + js .ssloop5 + mov esi, [_7z.StreamsInfo.tmpSubStreamsCRCsDefined] + mov al, [esi+edx] + mov esi, [_7z.StreamsInfo.SubStreamsCRCsDefined] + mov [esi+ecx], al + mov esi, [_7z.StreamsInfo.tmpSubStreamsCRCs] + mov eax, [esi+edx*4] + mov esi, [_7z.StreamsInfo.SubStreamsCRCs] + mov [esi+ecx*4], eax + inc edx + inc ecx + jmp @b +.ssend: + mov ecx, [_7z.StreamsInfo.tmpSubStreamsCRCsDefined] + call [pgfree] + and [_7z.StreamsInfo.tmpSubStreamsCRCsDefined], 0 + pop ecx + jmp .mainloop + +.folders_alloc: + push ecx + add ecx, [_7z.StreamsInfo.folders.size] + sub ecx, [_7z.StreamsInfo.folders.alloc] + jbe @f + push edx + or ecx, 0xFFF + inc ecx + add ecx, [_7z.StreamsInfo.folders.alloc] + mov [_7z.StreamsInfo.folders.alloc], ecx + mov edx, [_7z.StreamsInfo.folders] + call [pgrealloc] + pop edx + test eax, eax + jz return.clear + mov [_7z.StreamsInfo.folders], eax +@@: + pop ecx + mov eax, [_7z.StreamsInfo.folders.size] + add [_7z.StreamsInfo.folders.size], ecx + ret + +.error: + mov ecx, [_7z.StreamsInfo.packSizes] + jecxz @f + call [pgfree] +@@: + mov ecx, [_7z.StreamsInfo.folders] + jecxz @f + call [pgfree] +@@: + mov ecx, [_7z.StreamsInfo.SubStreamsSizes] + jecxz @f + call [pgfree] +@@: + mov ecx, [_7z.StreamsInfo.tmpSubStreamsCRCsDefined] + jecxz @f + call [pgfree] +@@: + jmp open_7z.header_error +.clear: + mov ecx, [_7z.StreamsInfo.packSizes] + jecxz @f + call [pgfree] +@@: + mov ecx, [_7z.StreamsInfo.folders] + jecxz @f + call [pgfree] +@@: + mov ecx, [_7z.StreamsInfo.SubStreamsSizes] + jecxz @f + call [pgfree] +@@: + mov ecx, [_7z.StreamsInfo.tmpSubStreamsCRCsDefined] + jecxz @f + call [pgfree] +@@: + jmp open_7z.clear + +uglobal +align 4 +_7z.decode.mainbuf dd ? +_7z.decode.pStreams dd ? +_7z.decode.pStreams_def rd 8 +_7z.decode.outBufferSize dd ? +_7z.decode.outBufferPtr dd ? +_7z.decode.outBufferRead dd ? +endg + +virtual at 0 +streamInfo: +.fullSize dq ? +.fillBuf dd ? ; procedure which fills the buffer +.bufSize dd ? +.bufDataLen dd ? +.bufPtr dd ? +.size = $ +end virtual + +_7z.decode: +; in: ebx->folder, outBufferSize, outBufferPtr +; N.B. We assume that every coder has 1 output (unpacked) stream. + and [.mainbuf], 0 + mov [.pStreams], .pStreams_def + mov [error_proc], .error + mov [clear_proc], .clear + call .init + and [.outBufferRead], 0 +@@: + push edi + mov eax, [ebx+_7z.StreamsInfo.mainOutStream] + mov esi, [.pStreams] + mov eax, [esi+eax*4] + call fillBuf + mov ecx, [eax+streamInfo.bufSize] + mov esi, [eax+streamInfo.bufPtr] + mov edi, [.outBufferPtr] + add edi, [.outBufferRead] + add [.outBufferRead], ecx + mov edx, ecx + shr ecx, 2 + rep movsd + mov ecx, edx + and ecx, 3 + rep movsb + pop edi + mov eax, [.outBufferRead] + cmp eax, [.outBufferSize] + jb @b + mov ecx, [.pStreams] + cmp ecx, .pStreams_def + jz @f + call [pgfree] +@@: + mov ecx, [.mainbuf] + jecxz @f + call [pgfree] +@@: + mov [error_proc], _7z.ReadAndDecodePackedStreams.error + mov [clear_proc], _7z.ReadAndDecodePackedStreams.clear + ret + +.error: + mov ecx, [.pStreams] + cmp ecx, .pStreams_def + jz @f + call [pgfree] +@@: + mov ecx, [.mainbuf] + jecxz @f + call [pgfree] +@@: + jmp _7z.ReadAndDecodePackedStreams.error +.clear: + mov ecx, [.pStreams] + cmp ecx, .pStreams_def + jz @f + call [pgfree] +@@: + mov ecx, [.mainbuf] + jecxz @f + call [pgfree] +@@: + jmp _7z.ReadAndDecodePackedStreams.clear + +.init: +; We use stack to keep some information on streams, +; to avoid stack overflow we limit possible number of coders. +; Anyway, in real life maximum number of coders is 5 +; (password protection filter + BCJ2 filter + 3 LZMA coders), +; from command line user can define more coders, but +; archive with, say, 32 coders is most likely bogus. + cmp [ebx+_7z.StreamsInfo.numCoders], 128 + ja return.err +; allocate space for streams info array + mov eax, .pStreams_def + mov ecx, [ebx+_7z.StreamsInfo.numPackedStreams] + add ecx, [ebx+_7z.StreamsInfo.numCoders] + cmp ecx, 8 + jbe @f + shl ecx, 2 + call [pgalloc] + test eax, eax + jz return.clear +@@: + mov [.pStreams], eax +; calculate size of buffers required for decoders + xor ecx, ecx + push ecx + mov ebp, [ebx+_7z.StreamsInfo.unpackSizes] +.calcbufsz: +; LZMA decoder: method ID = [size=03] 03 01 01, NumInStreams = NumOutStreams = 1 + mov eax, [ebx+_7z.StreamsInfo.fsz+ecx*4] + call _7z.GetCoder + jnc .known_id +.unknown_method_id: + movzx esi, byte [eax+4] + lea ecx, [eax+5] + mov ebx, aUnknownMethod.z +@@: + dec esi + js @f + mov byte [ebx], ' ' + inc ebx + mov al, [ecx] + push eax + shr al, 4 + cmp al, 10 + sbb al, 69h + das + mov [ebx], al + inc ebx + pop eax + and al, 0xF + cmp al, 10 + sbb al, 69h + das + mov [ebx], al + inc ebx + inc ecx + jmp @b +@@: + mov byte [ebx], 0 + push ContinueBtn + push 1 + push aUnknownMethod_ptr + push 1 + call [SayErr] + jmp return.clear +iglobal +if lang eq ru +aUnknownMethod db 'Неизвестный метод:' +else +aUnknownMethod db 'Unknown method:' +end if +.z: + times 16*3+1 db 0 +aUnknownMethod_ptr dd aUnknownMethod +endg +.known_id: + movzx esi, byte [eax+4] + lea esi, [esi+eax+17] + call [_7z.GetBufSizeTable+edx*4] + add eax, 3 + and al, not 3 + add [esp], eax + jc .nomem + cmp dword [ebp+4], 0 + jnz @f + cmp dword [ebp], edx + jae @f + mov edx, [ebp] +@@: + add edx, 0xF + and edx, not 0xF + add [esp], edx + jc .nomem + add ebp, 8 + inc ecx + cmp ecx, [ebx+_7z.StreamsInfo.numCoders] + jb .calcbufsz +; add 4 pages for each of not binded input streams + mov ecx, [ebx+_7z.StreamsInfo.numPackedStreams] + shl ecx, 14 + add [esp], ecx +;; calculate free RAM +; call [getfreemem] +; sub eax, 64 ; keep at least 64 Kb of free RAM +; jbe .nomem +; pop ecx +; push ecx +; add ecx, 0x3FF +; shr ecx, 10 +; cmp eax, ecx +; jae .memok + jmp .memok +.nomem: + push ContinueBtn + push 1 + push aNoFreeRam_ptr + push 1 + call [SayErr] + jmp return.clear +.memok: +; allocate streamInfos + pop ecx + call [pgalloc] + test eax, eax + jz return.clear + mov [.mainbuf], eax +; initialize streamInfos for decoders + xor ecx, ecx + mov ebp, [ebx+_7z.StreamsInfo.unpackSizes] + mov edx, [.pStreams] +.init1: + mov [edx], eax + add edx, 4 + push edx + push dword [ebp] + pop dword [eax] + push dword [ebp+4] + pop dword [eax+4] + and dword [eax+streamInfo.size], 0 + push eax + mov eax, [ebx+_7z.StreamsInfo.fsz+ecx*4] + call _7z.GetCoder + movzx esi, byte [eax+4] + lea esi, [esi+eax+17] + call [_7z.GetBufSizeTable+edx*4] + pop esi + push esi + add eax, 3 + and al, not 3 + add [esp], eax + pop [esi+streamInfo.bufPtr] + push [esi+streamInfo.bufPtr] + cmp dword [ebp+4], 0 + jnz @f + cmp dword [ebp], edx + jae @f + mov edx, [ebp] +@@: + add edx, 0xF + and edx, not 0xF + mov [esi+streamInfo.bufSize], edx + and [esi+streamInfo.bufDataLen], 0 + pop eax + add eax, edx + pop edx + add ebp, 8 + inc ecx + cmp ecx, [ebx+_7z.StreamsInfo.numCoders] + jb .init1 +; initialize streamInfos for input streams + xor ecx, ecx +@@: + mov [edx], eax + add edx, 4 + mov esi, [_7z.CurInStream] + inc [_7z.CurInStream] + shl esi, 3 + add esi, [_7z.StreamsInfo.packSizes] + push dword [esi] + pop dword [eax] + push dword [esi+4] + pop dword [eax+4] + mov [eax+streamInfo.fillBuf], fillBufFromInStream + lea esi, [eax+streamInfo.size+8] + mov [eax+streamInfo.bufPtr], esi + mov [eax+streamInfo.bufSize], 0x4000 - streamInfo.size - 8 + and [eax+streamInfo.bufDataLen], 0 + mov esi, dword [_7z.StreamsInfo.dataOffset] + mov dword [eax+streamInfo.size], esi + mov esi, dword [_7z.StreamsInfo.dataOffset+4] + mov dword [eax+streamInfo.size+4], esi + mov esi, [eax] + add dword [_7z.StreamsInfo.dataOffset], esi + mov esi, [eax+4] + adc dword [_7z.StreamsInfo.dataOffset+4], esi + add eax, 0x4000 + inc ecx + cmp ecx, [ebx+_7z.StreamsInfo.numPackedStreams] + jb @b +; initialize links between streams + push -1 + mov edx, [ebx+_7z.StreamsInfo.mainOutStream] + xor ecx, ecx +.init_links: + mov eax, [ebx+_7z.StreamsInfo.fsz+edx*4] + movzx esi, byte [eax+4] + cmp ecx, [eax+esi+5] + jb @f + pop ecx + cmp ecx, -1 + jz .inited_links + pop edx + jmp .init_links +@@: + push edx + push ecx +@@: + dec edx + js @f + mov eax, [ebx+_7z.StreamsInfo.fsz+edx*4] + movzx esi, byte [eax+4] + add ecx, [eax+esi+5] + jmp @b +@@: + mov esi, [ebx+_7z.StreamsInfo.bindPairs] + mov edx, [ebx+_7z.StreamsInfo.numBindPairs] +@@: + add esi, 8 + dec edx + js .link_to_in + cmp ecx, [esi-8] + jnz @b + pop ecx + pop edx + mov eax, [.pStreams] + mov eax, [eax+edx*4] + lea eax, [eax+streamInfo.size+ecx*4] + push edx + inc ecx + push ecx + mov edx, [esi-4] + mov ecx, [.pStreams] + mov ecx, [ecx+edx*4] + mov [eax], ecx + cmp dword [ecx+streamInfo.size], 0 + jnz return.err + xor ecx, ecx + jmp .init_links +.link_to_in: + mov esi, [ebx+_7z.StreamsInfo.packedStreams] + mov edx, [ebx+_7z.StreamsInfo.numPackedStreams] +@@: + dec edx + js return.err + cmp ecx, [esi+edx*4] + jnz @b + add edx, [ebx+_7z.StreamsInfo.numCoders] + mov esi, [.pStreams] + mov eax, [esi+edx*4] + pop ecx + pop edx + mov esi, [esi+edx*4] + mov [esi+streamInfo.size+ecx*4], eax + inc ecx + jmp .init_links +.inited_links: +; initialize all decoders +; bool zzz_init_decoder(stream_info* ebp, esi->params, [esi-4]=params_size); + xor ecx, ecx +.init_decoders: + mov eax, [ebx+_7z.StreamsInfo.fsz+ecx*4] + call _7z.GetCoder + movzx esi, byte [eax+4] + mov ebp, [.pStreams] + mov ebp, [ebp+ecx*4] + cmp dword [esi+eax], 0 + jz @f + cmp dword [ebp+streamInfo.size], 0 + jz return.err +@@: + lea esi, [esi+eax+17] + push ebx ecx edi + xor ebx, ebx + call [_7z.InitTable+edx*4] + pop edi ecx ebx + inc ecx + cmp ecx, [ebx+_7z.StreamsInfo.numCoders] + jb .init_decoders + ret + +fillBuf: + and [eax+streamInfo.bufDataLen], 0 +fillBufNozero: + pushad + mov edx, [eax+streamInfo.bufSize] + sub edx, [eax+streamInfo.bufDataLen] + cmp dword [eax+streamInfo.fullSize+4], 0 + jnz .full + mov ecx, dword [eax+streamInfo.fullSize] + cmp ecx, edx + jbe @f +.full: + mov ecx, edx +@@: + sub dword [eax+streamInfo.fullSize], ecx + sbb dword [eax+streamInfo.fullSize+4], 0 + mov edi, [eax+streamInfo.bufPtr] + add edi, [eax+streamInfo.bufDataLen] + add [eax+streamInfo.bufDataLen], ecx + jmp [eax+streamInfo.fillBuf] + +fillBufFromInStream: + push eax + push dword [eax+streamInfo.size+4] + push dword [eax+streamInfo.size] + push 0 + push [inStream] + call [seek] + pop eax + push eax + push ecx + push edi + push [inStream] + call [read] + cmp eax, ecx + pop eax + jnz .error + add dword [eax+streamInfo.size], ecx + adc dword [eax+streamInfo.size+4], 0 + popad + ret +.error: + push ContinueBtn + push 1 + push aReadError_ptr + push 1 + call [SayErr] + jmp return.clear + +_7z.GetCoder: +; in: eax->coder +; out: edx = coder type + xor edx, edx +; Copy decoder: method ID = [size=01] 00, NumInStreams = NumOutStreams = 1 + cmp word [eax+4], 0x0001 + jnz @f + cmp dword [eax+6], 1 + jz .ret +@@: + inc edx +; LZMA decoder: method ID = [size=03] 03 01 01, NumInStreams = NumOutStreams = 1 + cmp dword [eax+4], 0x01010303 + jnz @f + cmp dword [eax+8], 1 + jz .ret +@@: + inc edx +; PPMD decoder: method ID = [size=03] 03 04 01, NumInStreams = NumOutStreams = 1 + cmp dword [eax+4], 0x01040303 + jnz @f + cmp dword [eax+8], 1 + jz .ret +@@: + inc edx +; BCJ filter: method ID = [size=04] 03 03 01 03, NumInStreams = NumOutStreams = 1 + cmp byte [eax+4], 4 + jnz @f + cmp dword [eax+5], 0x03010303 + jnz @f + cmp dword [eax+9], 1 + jz .ret +@@: + inc edx +; BCJ2 filter: method ID = [size=04] 03 03 01 1B, NumInStreams = 4, NumOutStreams = 1 + cmp byte [eax+4], 4 + jnz @f + cmp dword [eax+5], 0x1B010303 + jnz @f + cmp dword [eax+9], 4 + jz .ret +@@: + inc edx +; 7z-AES cryptor: method ID = [size=04] 06 F1 07 01, NumInStreams = NumOutStreams = 1 + cmp byte [eax+4], 4 + jnz @f + cmp dword [eax+5], 0x0107F106 + jnz @f + cmp dword [eax+9], 1 + jz .ret +@@: + stc +.ret: + ret + +iglobal +align 4 +label _7z.GetBufSizeTable dword + dd copy_get_buf_size + dd lzma_get_buf_size + dd ppmd_get_buf_size + dd bcj_get_buf_size + dd bcj2_get_buf_size + dd aes7z_get_buf_size +label _7z.InitTable dword + dd copy_init_decoder + dd lzma_init_decoder + dd ppmd_init_decoder + dd bcj_init_decoder + dd bcj2_init_decoder + dd aes7z_init_decoder +endg + +copy_get_buf_size: + mov eax, streamInfo.size+8 + mov edx, 0x10000 + ret + +copy_init_decoder: + mov [ebp+streamInfo.fillBuf], copy_fillBuf + and dword [ebp+streamInfo.size+4], 0 + ret + +copy_fillBuf: + push eax + mov esi, [eax+streamInfo.size+4] + mov eax, [eax+streamInfo.size] +.redo: + push ecx + mov edx, [eax+streamInfo.bufDataLen] + sub edx, esi + cmp ecx, edx + jb @f + mov ecx, edx +@@: + sub [esp], ecx + add esi, [eax+streamInfo.bufPtr] + mov edx, ecx + shr ecx, 2 + rep movsd + mov ecx, edx + and ecx, 3 + rep movsb + pop ecx + jecxz .done + cmp dword [eax+streamInfo.fullSize+4], 0 + jnz @f + cmp dword [eax+streamInfo.fullSize], ecx + jb return.err +@@: + call fillBuf + xor esi, esi + jmp .redo +.done: + sub esi, [eax+streamInfo.bufPtr] + pop eax + mov [eax+streamInfo.size+4], esi + popad + ret + +; int __stdcall ReadFolder([esp+4] = HANDLE hPlugin, +; [esp+8] = unsigned dirinfo_start, [esp+12] = unsigned dirinfo_size, +; [esp+16] = void* dirdata); +ReadFolder_7z: +; init header + mov edi, [esp+16] + mov ecx, 32/4 + xor eax, eax + rep stosd + mov byte [edi-32], 1 ; version + mov ebp, [esp+4] +; get current directory + lea ebx, [ebp+handle_7z.root.subfolders] + cmp [ebp+handle_7z.curdir], 0 + jz @f + mov ebx, [ebp+handle_7z.curdir] + add ebx, file_in_7z.subfolders +@@: + mov ecx, [ebx+16] + mov [edi-24], ecx ; number of files +; edi points to BDFE + push 6 ; assume EOF + pop eax + sub ecx, [esp+8] + ja @f + and dword [edi-28], 0 ; number of files read + ret 10h +@@: + cmp ecx, [esp+12] + jb @f + mov ecx, [esp+12] + xor eax, eax ; OK +@@: + mov [edi-28], ecx + push eax +; copy files data + test ecx, ecx + jz .done +; seek to required item + mov eax, [esp+8+4] + mov esi, [ebx] +.0: + test esi, esi + jnz .1 + mov esi, [ebx+8] +.1: + add esi, ebp + dec eax + js .2 + mov esi, [esi+file_in_7z.next] + jmp .0 +.2: +.copy: + cmp [esi+file_in_7z.bPseudoFolder], 0 + jnz .pseudo + xor eax, eax + cmp [esi+file_in_7z.bAttrDefined], 0 + jz @f + mov eax, [esi+file_in_7z.attr] +@@: + stosd + xor eax, eax + stosd + push esi ecx + add esi, file_in_7z.CreationTime + mov ecx, 8 + rep movsd + pop ecx esi + mov edx, [esi+file_in_7z.name] + push edi +@@: + mov al, [edx] + inc edx + stosb + test al, al + jnz @b + pop edi +.cont: + add edi, 264 + mov esi, [esi+file_in_7z.next] + test esi, esi + jnz @f + mov esi, [ebx+8] +@@: + add esi, ebp + loop .copy + jmp .done +.pseudo: + push 0x10 ; attributes: folder + pop eax + stosd + xor eax, eax + stosd + push ecx esi + lea esi, [ebp+handle_7z.host_datetime] + mov ecx, 6 + rep movsd + pop esi + stosd + stosd + push edi esi + mov ecx, [esi+file_in_7z.namelen] + mov esi, [esi+file_in_7z.name] + rep movsb + mov byte [edi], 0 + pop esi edi ecx + jmp .cont +.done: + pop eax + ret 10h + +; bool __stdcall SetFolder([esp+4] = HANDLE hPlugin, +; [esp+8] = const char* relative_path, [esp+12] = const char* absolute_path); +SetFolder_7z: + mov ebp, [esp+4] + mov edx, [ebp+handle_7z.curdir] + mov esi, [esp+8] + cmp dword [esi], '..' + jz .toparent + xor ecx, ecx +@@: + inc ecx + cmp byte [esi+ecx], 0 + jnz @b + mov ebx, [ebp+handle_7z.root.subfolders] + test edx, edx + jz .scan + mov ebx, [edx+file_in_7z.subfolders] +.scan: + test ebx, ebx + jz .err + add ebx, ebp + cmp [ebx+file_in_7z.namelen], ecx + jnz .cont + push ecx esi + mov edi, [ebx+file_in_7z.name] + repz cmpsb + pop esi ecx + jz .set +.cont: + mov ebx, [ebx+file_in_7z.next] + jmp .scan +.toparent: + test edx, edx + jz .err + mov ebx, [edx+file_in_7z.parent] + test ebx, ebx + jz @f + add ebx, ebp +@@: +.set: + mov [ebp+handle_7z.curdir], ebx + mov al, 1 + ret 12 +.err: + xor eax, eax + ret 12 + +; ebp=hPlugin, eax->item, edi->info +getattr_7z: + cmp [eax+file_in_7z.bPseudoFolder], 0 + jnz .pseudo + lea esi, [eax+file_in_7z.attr] + movsd + xor eax, eax + stosd + add esi, -(file_in_7z.attr+4) + file_in_7z.CreationTime + mov ecx, 8 + rep movsd + ret +.pseudo: + mov esi, [eax+file_in_7z.name] + mov ecx, [eax+file_in_7z.namelen] + push 0x10 ; attributes: folder + pop eax + stosd + xor eax, eax + stosd + push ecx esi + lea esi, [ebp+handle_7z.host_datetime] + push 6 + pop ecx + rep movsd + pop esi ecx + stosd + stosd + rep movsb + mov byte [edi], 0 + ret + +virtual at 0 +file_handle_7z: +.type dd ? +.context dd ? +.pos dq ? +.base dd ? ; handle of archive +.item dd ? ; pointer to file_in_7z +.mainStream dd ? ; (pointer in context) +.bError db ? + rb 3 +.size = $ +end virtual + +iglobal +align 4 +handle_table_7z dd handle_table_7z,handle_table_7z +endg + +; ebp=hPlugin, eax->item, edi=mode +open_file_7z: + cmp [eax+file_in_7z.bHasStream], 0 + jnz @f + mov eax, empty_7z_handle + ret +@@: + mov ecx, [ebp+handle_7z.password_len] + inc ecx + setnz [bPasswordDefined] + jz @f + dec ecx + lea esi, [ebp+handle_7z.password] + push edi + mov edi, password_unicode + shr ecx, 1 + rep movsd + adc ecx, ecx + rep movsw + pop edi +@@: + mov [hOut], ecx + mov [_7z.decode.mainbuf], ecx + mov ecx, [ebp+handle_7z.host] + mov [inStream], ecx + mov [_7z.decode.pStreams], _7z.decode.pStreams_def + push eax + mov [_esp], esp + mov [_ebp], ebp + mov [error_proc], .error + mov [clear_proc], .clear + mov ebx, [ebp+handle_7z.folders] + mov ecx, [eax+file_in_7z.folder] + cmp [ebp+handle_7z.last_folder], ecx + jnz .nolast + mov edx, dword [eax+file_in_7z.folderStart] + sub edx, dword [ebp+handle_7z.last_pos] + mov esi, dword [eax+file_in_7z.folderStart+4] + sbb esi, dword [ebp+handle_7z.last_pos+4] + jb .nolast + xor ecx, ecx + xchg ecx, [ebp+handle_7z.last_context] + mov [_7z.decode.mainbuf], ecx + mov eax, [ebp+handle_7z.last_main_stream] + mov dword [eax+streamInfo.fullSize], edx + mov dword [eax+streamInfo.fullSize+4], esi + or [ebp+handle_7z.last_folder], -1 + pop esi + push esi + jmp .commonl +.nolast: + mov ebx, [ebx+ecx*4] + mov eax, [ebx+_7z.StreamsInfo.startPackedStream] + mov [_7z.CurInStream], eax + mov eax, dword [ebx+_7z.StreamsInfo.packOffset] + mov dword [_7z.StreamsInfo.dataOffset], eax + mov eax, dword [ebx+_7z.StreamsInfo.packOffset+4] + mov dword [_7z.StreamsInfo.dataOffset+4], eax + mov eax, [ebp+handle_7z.packSizes] + mov [_7z.StreamsInfo.packSizes], eax + push ebp + call _7z.decode.init + pop ebp + mov eax, [ebx+_7z.StreamsInfo.mainOutStream] + mov esi, [_7z.decode.pStreams] + mov eax, [esi+eax*4] + pop esi + push esi + mov ecx, dword [esi+file_in_7z.folderStart] + mov dword [eax+streamInfo.fullSize], ecx + mov ecx, dword [esi+file_in_7z.folderStart+4] + mov dword [eax+streamInfo.fullSize+4], ecx +.commonl: + call skip_7z + mov ecx, dword [esi+file_in_7z.UnPackSize] + mov dword [eax+streamInfo.fullSize], ecx + mov edx, dword [esi+file_in_7z.UnPackSize+4] + mov dword [eax+streamInfo.fullSize+4], edx + test edx, edx + jnz .nomemstream +if defined LIMIT_FOR_MEM_STREAM + cmp ecx, LIMIT_FOR_MEM_STREAM + ja .nomemstream +end if + push eax ecx + add ecx, 0x3FF + shr ecx, 10 ; get size in Kb + call [getfreemem] + shr eax, 2 + cmp ecx, eax + pop ecx eax + ja .nomemstream +; create memory stream and unpack to memory + push eax ecx + add ecx, mem_stream.buf + call [pgalloc] + test eax, eax + jz return.clear + mov edi, eax + pop ecx + push edi + mov [hOut], eax + xor eax, eax ; type_mem_stream + stosd ; mem_stream.type + mov eax, ecx + stosd ; mem_stream.size + xor eax, eax + stosd ; mem_stream.pos + mov eax, [esp+4] + push esi + push ecx edi + call read_7z_to_buf + pop esi ecx + mov ebx, [esp+12] + cmp [ebx+file_in_7z.bCRCDefined], 0 + jz @f + call crc + cmp eax, [ebx+file_in_7z.FileCRC] + jnz return.err +@@: + pop esi + xor ecx, ecx + xchg ecx, [_7z.decode.mainbuf] + xchg ecx, [ebp+handle_7z.last_context] + jecxz @f + call [pgfree] +@@: + and [hOut], 0 + mov eax, [esi+file_in_7z.folder] + mov [ebp+handle_7z.last_folder], eax + mov eax, [esp+4] + mov [ebp+handle_7z.last_main_stream], eax + mov ecx, dword [esi+file_in_7z.UnPackSize] + add ecx, dword [esi+file_in_7z.folderStart] + mov dword [ebp+handle_7z.last_pos], ecx + mov ecx, dword [esi+file_in_7z.UnPackSize+4] + adc ecx, dword [esi+file_in_7z.folderStart+4] + mov dword [ebp+handle_7z.last_pos+4], ecx + call .done + pop eax edi ecx + ret +.nomemstream: + mov edi, eax + push esi + mov esi, handle_table_7z + push file_handle_7z.size + pop ecx + call alloc_handle + pop esi + test eax, eax + jz .clear + mov [eax+file_handle_7z.type], type_7z + xor edx, edx + mov dword [eax+file_handle_7z.pos], edx + mov dword [eax+file_handle_7z.pos+4], edx + mov [eax+file_handle_7z.bError], dl + xchg edx, [_7z.decode.mainbuf] + mov [eax+file_handle_7z.context], edx + mov [eax+file_handle_7z.mainStream], edi + mov [eax+file_handle_7z.base], ebp + mov [eax+file_handle_7z.item], esi + push eax + call .done + pop eax ecx + ret + +.done: + cmp [bPasswordDefined], 0 + jz @f + mov ecx, [password_size] + mov [ebp+handle_7z.password_len], ecx + mov esi, password_unicode + lea edi, [ebp+handle_7z.password] + shr ecx, 1 + rep movsd + adc ecx, ecx + rep movsw +@@: + jmp .clear + +.error: + cmp [bPasswordDefined], 0 + jz .realerror + push CancelPassBtn + push 2 + push aArchiveDataErrorPass_ptr + push 1 + call [SayErr] + cmp al, 1 + jnz .clear +; user wants to re-enter password + call .clear + pop eax + jmp open_file_7z +.realerror: + push ContinueBtn + push 1 + push aArchiveDataError_ptr + push 1 + call [SayErr] +.clear: + mov ecx, [_7z.decode.pStreams] + cmp ecx, _7z.decode.pStreams_def + jz @f + call [pgfree] +@@: + mov ecx, [_7z.decode.mainbuf] + jecxz @f + call [pgfree] +@@: + mov ecx, [hOut] + jecxz @f + call [pgfree] +@@: + cmp esp, [_esp] + jnz @f + pop eax +@@: + xor eax, eax + ret + +read_7z_to_buf: + mov esi, [eax+streamInfo.bufDataLen] + cmp esi, [eax+streamInfo.bufSize] + jnz @f + xor esi, esi + mov [eax+streamInfo.bufDataLen], esi +@@: + call fillBufNozero + mov ecx, [eax+streamInfo.bufDataLen] + sub ecx, esi + add esi, [eax+streamInfo.bufPtr] + mov edx, ecx + shr ecx, 2 + rep movsd + mov ecx, edx + and ecx, 3 + rep movsb + cmp dword [eax+streamInfo.fullSize], 0 + jnz read_7z_to_buf + ret + +skip_7z: + push edx + mov edx, [eax+streamInfo.bufDataLen] + cmp edx, [eax+streamInfo.bufSize] + jnz @f + and [eax+streamInfo.bufDataLen], 0 +@@: + pop edx + call fillBufNozero + cmp dword [eax+streamInfo.fullSize], 0 + jnz skip_7z + cmp dword [eax+streamInfo.fullSize+4], 0 + jnz skip_7z + ret + +; unsigned __stdcall read(HANDLE hFile, void* buf, unsigned size); +read_7z: + mov eax, [ebx+file_handle_7z.mainStream] + test eax, eax + jz .ret ; empty stream - return 0 bytes read + cmp [ebx+file_handle_7z.bError], 0 + jnz .reterr + mov ecx, [ebx+file_handle_7z.base] + mov ecx, [ecx+handle_7z.host] + mov [inStream], ecx + mov edi, [esp+8] + mov ecx, [esp+12] + mov dword [eax+streamInfo.fullSize], ecx + and dword [eax+streamInfo.fullSize+4], 0 + jecxz .nodata + mov [_esp], esp + mov [_ebp], ebp + mov [error_proc], .error + mov [clear_proc], .clear ; should not be called + mov esi, [ebx+file_handle_7z.item] + mov edx, dword [esi+file_in_7z.UnPackSize] + mov esi, dword [esi+file_in_7z.UnPackSize+4] + sub edx, dword [ebx+file_handle_7z.pos] + sbb esi, dword [ebx+file_handle_7z.pos+4] + jnz .do + cmp edx, ecx + jae .do + mov dword [eax+streamInfo.fullSize], edx +.do: + call read_7z_to_buf +.nodata: + sub edi, [esp+8] + mov eax, edi + add dword [ebx+file_handle_7z.pos], eax + adc dword [ebx+file_handle_7z.pos+4], 0 +.ret: + ret 12 + +.error: +.clear: + mov ebx, [esp+4] + mov [ebx+file_handle_7z.bError], 1 + push ContinueBtn + push 1 + push aArchiveDataError_ptr + push 1 + call [SayErr] +.reterr: + or eax, -1 + ret 12 + +; void __stdcall setpos(HANDLE hFile, __int64 pos); +setpos_7z: + cmp [ebx+file_handle_7z.context], 0 + jz .ret + mov edi, [ebx+file_handle_7z.base] + mov ecx, [edi+handle_7z.host] + mov [inStream], ecx + mov [_esp], esp + mov [_ebp], ebp + mov [error_proc], read_7z.error + mov [clear_proc], read_7z.clear ; should not be called + cmp [ebx+file_handle_7z.bError], 0 + jnz .backward ; if was error, force reinitialization + mov ecx, [esp+8] + mov edx, [esp+12] + sub ecx, dword [ebx+file_handle_7z.pos] + sbb edx, dword [ebx+file_handle_7z.pos+4] + jb .backward +; move forward - skip some data + mov eax, [ebx+file_handle_7z.mainStream] + mov dword [eax+streamInfo.fullSize], ecx + mov dword [eax+streamInfo.fullSize+4], edx + call skip_7z + add dword [ebx+file_handle_7z.pos], ecx + adc dword [ebx+file_handle_7z.pos], edx +.ret: + ret 12 +.backward: +; move backward - reinitialize and skip start data + mov [ebx+file_handle_7z.bError], 0 + mov ebp, [ebx+file_handle_7z.context] + mov eax, [ebx+file_handle_7z.item] + mov ebx, [edi+handle_7z.folders] + mov eax, [eax+file_in_7z.folder] + mov ebx, [ebx+eax*4] +; initialize streamInfos for decoders + xor ecx, ecx + mov esi, [ebx+_7z.StreamsInfo.unpackSizes] +@@: + lodsd + mov [ebp], eax + lodsd + mov [ebp+4], eax + and [ebp+streamInfo.bufDataLen], 0 + push esi + mov eax, [ebx+_7z.StreamsInfo.fsz+ecx*4] + call _7z.GetCoder + movzx esi, byte [eax+4] + lea esi, [esi+eax+17] + push ebx ecx edi + mov bl, 1 + call [_7z.InitTable+edx*4] + pop edi ecx ebx esi + mov edx, [ebp+streamInfo.bufSize] + mov ebp, [ebp+streamInfo.bufPtr] + add ebp, edx + inc ecx + cmp ecx, [ebx+_7z.StreamsInfo.numCoders] + jb @b +; initialize streamInfos for input streams + xor ecx, ecx + mov esi, [ebx+_7z.StreamsInfo.startPackedStream] + shl esi, 3 + add esi, [edi+handle_7z.packSizes] + mov edi, dword [ebx+_7z.StreamsInfo.packOffset] + mov edx, dword [ebx+_7z.StreamsInfo.packOffset+4] +@@: + mov dword [ebp+streamInfo.size], edi + mov dword [ebp+streamInfo.size+4], edx + and [ebp+streamInfo.bufDataLen], 0 + lodsd + add edi, eax + mov [ebp], eax + lodsd + adc edx, eax + mov [ebp+4], eax + add ebp, 0x4000 + inc ecx + cmp ecx, [ebx+_7z.StreamsInfo.numPackedStreams] + jb @b + mov ebx, [esp+4] + mov esi, [ebx+file_handle_7z.item] + mov eax, [ebx+file_handle_7z.mainStream] + mov ecx, dword [esi+file_in_7z.folderStart] + add ecx, [esp+8] + mov dword [eax+streamInfo.fullSize], ecx + mov ecx, dword [esi+file_in_7z.folderStart+4] + adc ecx, [esp+12] + mov dword [eax+streamInfo.fullSize+4], ecx + and dword [ebx+file_handle_7z.pos], 0 + and dword [ebx+file_handle_7z.pos+4], 0 + and [eax+streamInfo.bufDataLen], 0 + call skip_7z + mov eax, [esp+8] + mov dword [ebx+file_handle_7z.pos], eax + mov eax, [esp+12] + mov dword [ebx+file_handle_7z.pos+4], eax + ret 12 + +close_file_7z: + mov ecx, [ebx+file_handle_7z.context] + jecxz .ret + cmp [ebx+file_handle_7z.bError], 0 + jnz @f + push ebp + mov ebp, [ebx+file_handle_7z.base] + xchg ecx, [ebp+handle_7z.last_context] + mov eax, [ebx+file_handle_7z.item] + mov edx, [eax+file_in_7z.folder] + mov [ebp+handle_7z.last_folder], edx + mov edx, [ebx+file_handle_7z.mainStream] + mov [ebp+handle_7z.last_main_stream], edx + mov edx, dword [eax+file_in_7z.folderStart+4] + mov eax, dword [eax+file_in_7z.folderStart] + add eax, dword [ebx+file_handle_7z.pos] + adc edx, dword [ebx+file_handle_7z.pos+4] + mov dword [ebp+handle_7z.last_pos], eax + mov dword [ebp+handle_7z.last_pos+4], edx + pop ebp +@@: + jecxz @f + call [pgfree] +@@: + mov esi, ebx + call free_handle +.ret: + ret 4 + +iglobal +cur_stamp dd 0 +endg + +uglobal +tmp_bdfe rb 304 +endg + +GetFiles_7z: + mov ecx, [ebp+handle_7z.NumFiles] + test ecx, ecx + jz .ret + lea ebx, [ebp+handle_7z.basesize] + inc [cur_stamp] +.loop: + push ecx + mov esi, [ebx+file_in_7z.fullname] + mov edx, [ebp+handle_7z.curdir] + test edx, edx + jz .incur + mov eax, [cur_stamp] + mov [edx+file_in_7z.stamp], eax + mov edi, [edx+file_in_7z.fullname] + mov ecx, [edx+file_in_7z.namelen] + add ecx, [edx+file_in_7z.name] + sub ecx, edi + repz cmpsb + jnz .cont +.incur: + cmp byte [esi], '/' + jnz @f + inc esi +@@: + mov ecx, [esp+12] ; NumItems + mov edx, [esp+16] ; items + cmp ecx, -1 + jz .ok +.check: + sub ecx, 1 + js .cont + push esi + mov edi, [edx] + add edi, 40 +@@: + lodsb + scasb + jnz @f + test al, al + jz .ok2 + jmp @b +@@: + pop esi + cmp al, '/' + jnz @f + cmp byte [edi-1], 0 + jz .ok +@@: + add edx, 4 + jmp .check +.ok2: + pop esi +.ok: +; add all parents directories if needed +.parloope: + mov ecx, [ebx+file_in_7z.parent] + jecxz .pardone + add ecx, ebp + mov eax, [cur_stamp] + cmp [ecx+file_in_7z.stamp], eax + jz .pardone +.parloopi: + mov edx, ecx + mov ecx, [ecx+file_in_7z.parent] + jecxz @f + add ecx, ebp + cmp [ecx+file_in_7z.stamp], eax + jnz .parloopi +@@: + mov [edx+file_in_7z.stamp], eax + push esi + mov eax, edx + mov edi, tmp_bdfe + push edi + sub esi, [ebx+file_in_7z.fullname] + add esi, [edx+file_in_7z.fullname] + push esi + call getattr_7z + mov eax, [esp+16+20] + call eax + pop esi + test al, al + jz .forced_exit + jmp .parloope +.pardone: + cmp [ebx+file_in_7z.bIsDirectory], 0 + jz .addfile + mov eax, [cur_stamp] + cmp [ebx+file_in_7z.stamp], eax + jz .cont + mov [ebx+file_in_7z.stamp], eax + push esi + mov eax, ebx + mov edi, tmp_bdfe + push edi + push esi + call getattr_7z + mov eax, [esp+16+20] + call eax + pop esi + test al, al + jz .forced_exit + jmp .cont +.addfile: + push ebx esi + push 11h + pop edi + mov eax, ebx + call open_file_7z + pop esi ebx + test eax, eax + jz .cont + push eax + push eax + mov edi, tmp_bdfe + push edi + push esi + mov eax, ebx + call getattr_7z + mov eax, [esp+20+16] + call eax + pop ecx + push eax + push ebx + push ecx + call myclose + pop ebx + pop eax + test al, al + jz .forced_exit +.cont: + add ebx, file_in_7z.size + pop ecx + dec ecx + jnz .loop +.ret: + ret 20 +.forced_exit: + pop ecx + jmp .ret diff --git a/programs/fs/kfar/trunk/kfar_arc/7zaes.inc b/programs/fs/kfar/trunk/kfar_arc/7zaes.inc new file mode 100644 index 0000000000..66148eba09 --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/7zaes.inc @@ -0,0 +1,216 @@ +; Password handling in 7-Zip: "7zAES" filter (SHA256 + AES256). +; Ported from C++ sources of 7-Zip (c) Igor Pavlov. +aes7z_decoder: +virtual at 0 +.outStream rb streamInfo.size +.inStream dd ? +.inLen dd ? +.inPtr dd ? +.bufRest dd ? +; key data +.NumCyclesPower dd ? +.SaltSize dd ? +.Salt rb 16 +; AES data +.iv rb 16 +.Key rb 32 +.nr dd ? +.KeyExpanded rb 32*15 +.size = $ +end virtual + +.fillBuf: + mov esi, [eax+.inPtr] + mov ebp, eax + add edi, [eax+.bufRest] + sub ecx, [eax+.bufRest] + js .rest1 + and [eax+.bufRest], 0 +.mainloop: + test ecx, ecx + jz .done + sub [ebp+.inLen], 16 + js .refill +.refilled: + push esi edi ecx + mov ebx, edi + lea edi, [ebp+.nr] + call aes_decode + pop ecx edi esi + mov eax, dword [ebp+.iv] + xor [edi], eax + lodsd + mov dword [ebp+.iv], eax + mov eax, dword [ebp+.iv+4] + xor [edi+4], eax + lodsd + mov dword [ebp+.iv+4], eax + mov eax, dword [ebp+.iv+8] + xor [edi+8], eax + lodsd + mov dword [ebp+.iv+8], eax + mov eax, dword [ebp+.iv+12] + xor [edi+12], eax + lodsd + mov dword [ebp+.iv+12], eax + add edi, 16 + sub ecx, 16 + jns .mainloop +.rest1: + neg ecx + mov [ebp+.bufRest], ecx +.done: + mov [ebp+.inPtr], esi + popad + ret + +.refill: + mov edx, [ebp+.inLen] + add edx, 16 + jnz .rest + js return.err + mov eax, [ebp+.inStream] + call fillBuf + mov edx, [eax+streamInfo.bufDataLen] + test edx, edx + jz return.err + mov esi, [eax+streamInfo.bufPtr] + mov [ebp+.inLen], edx + sub [ebp+.inLen], 16 + jns .refilled +.rest: +; ASSERT([eax+streamInfo.fullSize] == 0); + sub edx, ecx + jb return.err + add ecx, edx + rep movsb + mov [ebp+.bufRest], edx + jmp .done + +aes7z_get_buf_size: + mov eax, aes7z_decoder.size + mov edx, 0x4000 + ret + +aes7z_init_decoder: +; zero all + xor eax, eax + mov [ebp+aes7z_decoder.inLen], eax + mov [ebp+aes7z_decoder.bufRest], eax + mov [ebp+aes7z_decoder.NumCyclesPower], eax + mov [ebp+aes7z_decoder.SaltSize], eax + lea edi, [ebp+aes7z_decoder.Salt] + push 8 + pop ecx + rep stosd ; zero .Salt and .iv + mov [ebp+streamInfo.fillBuf], aes7z_decoder.fillBuf +; parse parameters + cmp dword [esi-4], eax + jz .parok ; no parameters - OK + lodsb + mov cl, al + and al, 0x3F + mov byte [ebp+aes7z_decoder.NumCyclesPower], al + test cl, 0xC0 + jz .parok + test cl, 0x80 + setnz byte [ebp+aes7z_decoder.SaltSize] + shr cl, 6 + and ecx, 1 + cmp dword [esi-1-4], 2 + jb return.err + lodsb + mov dl, al + shr al, 4 + add byte [ebp+aes7z_decoder.SaltSize], al + and edx, 0xF + add ecx, edx + lea edx, [ecx+2] + push ecx + mov ecx, [ebp+aes7z_decoder.SaltSize] + add edx, ecx + cmp dword [esi-2-4], edx + jb return.err + lea edi, [ebp+aes7z_decoder.Salt] + rep movsb + pop ecx + lea edi, [ebp+aes7z_decoder.iv] + rep movsb +.parok: + test bl, bl + jnz .ret ; if reinitializing - all calculations have been already done + call query_password + jz return.clear +;.CalculateDigest: + mov cl, byte [ebp+aes7z_decoder.NumCyclesPower] + cmp cl, 0x3F + jnz .sha + lea edi, [ebp+aes7z_decoder.Key] + mov ecx, [ebp+aes7z_decoder.SaltSize] + push 32 + pop edx + sub edx, ecx + lea esi, [ebp+aes7z_decoder.Salt] + rep movsb + mov ecx, [password_size] + add ecx, ecx + cmp ecx, edx + jbe @f + mov ecx, edx +@@: + sub edx, ecx + mov esi, password_unicode + rep movsb + mov ecx, edx + xor eax, eax + rep stosb + jmp .setkey +.sha: + cmp cl, 32 + jb .normal + push 1 + shl dword [esp], cl + push 0 + jmp @f +.normal: + push 0 + push 1 + shl dword [esp], cl +@@: + push 0 + push 0 + call sha256_init +.loop: + lea esi, [ebp+aes7z_decoder.Salt] + mov edx, [ebp+aes7z_decoder.SaltSize] + call sha256_update + mov esi, password_unicode + mov edx, [password_size] + add edx, edx + call sha256_update + mov esi, esp + push 8 + pop edx + call sha256_update + mov esi, esp + dec esi +@@: + inc esi + inc byte [esi] + jz @b + sub dword [esp+8], 1 + sbb dword [esp+12], 0 + mov eax, [esp+8] + or eax, [esp+12] + jnz .loop + lea edi, [ebp+aes7z_decoder.Key] + call sha256_final + add esp, 16 +.setkey: + lea esi, [ebp+aes7z_decoder.Key] + push 8 + pop edx ; 7z uses 256-bit keys + lea edi, [ebp+aes7z_decoder.nr] + call aes_setkey +.ret: + ret diff --git a/programs/fs/kfar/trunk/kfar_arc/7zbranch.inc b/programs/fs/kfar/trunk/kfar_arc/7zbranch.inc new file mode 100644 index 0000000000..8fe6c1f892 --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/7zbranch.inc @@ -0,0 +1,469 @@ +; Branch filters for 7-Zip archives: BCJ and BCJ2. +; Ported from C++ sources of 7-Zip (c) Igor Pavlov. +virtual at 0 +bcj_decoder: +.outStream rb streamInfo.size +.inStream dd ? +.inPtr dd ? +.inSize dd ? +.nowPos dd ? ; offset in stream +.prevPos dd ? ; pointer in buffer +.prevMask db ? +.numRest db ? + rw 1 +.dwordRest dd ? +.tempSize dd ? +.tempDword dd ? +.size = $ +end virtual + +bcj_get_buf_size: + mov eax, bcj_decoder.size + mov edx, 0x4000 + ret + +bcj_init_decoder: + mov [ebp+streamInfo.fillBuf], bcj_fillBuf + xor edx, edx + mov [ebp+bcj_decoder.inPtr], edx + mov [ebp+bcj_decoder.inSize], edx + mov [ebp+bcj_decoder.prevPos], edx + mov [ebp+bcj_decoder.nowPos], edx + mov [ebp+bcj_decoder.numRest], dl + ret + +bcj_fillBuf: + add [eax+bcj_decoder.nowPos], ecx + mov ebp, ecx ; save output size + mov esi, [eax+bcj_decoder.inPtr] + mov ebx, [eax+bcj_decoder.inStream] + mov ecx, [eax+bcj_decoder.inSize] + add esi, [ebx+streamInfo.bufPtr] + mov ebx, eax + cmp [eax+bcj_decoder.prevPos], 0 + jz @f + add [eax+bcj_decoder.prevPos], edi +@@: + cmp [ebx+bcj_decoder.numRest], 0 + jz .mainloop + sub ebp, 1 + js .mainloopdone + dec [ebx+bcj_decoder.numRest] + mov eax, [ebx+bcj_decoder.dwordRest] + stosb + shr eax, 8 + mov [ebx+bcj_decoder.dwordRest], eax + jmp @b +.mainloop: + sub ebp, 1 + js .mainloopdone + sub ecx, 1 + js .refill1 +.filled1: + lodsb +.filled2: + stosb + cmp al, 0xE8 + jz .filter + cmp al, 0xE9 + jnz .mainloop +.filter: + and [ebx+bcj_decoder.tempSize], 0 + sub ecx, 4 + jb .nopos + js .nopos2 + lodsd + push eax +.posok: + xor edx, edx + mov eax, edi + sub eax, [ebx+bcj_decoder.prevPos] + cmp eax, 5 + ja .maskok + movzx edx, [ebx+bcj_decoder.prevMask] +@@: + and edx, 0x77 + add edx, edx + sub eax, 1 + jnz @b +.maskok: + mov [ebx+bcj_decoder.prevMask], dl + mov [ebx+bcj_decoder.prevPos], edi + mov al, [esp+3] + add al, 1 + cmp al, 2 + jae .miss + cmp dl, 0x20 + jae .miss2 + lea eax, [edx-1] + test eax, edx + jnz .miss2 + pop eax + shr edx, 1 + push ecx + mov cl, [bcj_kMaskToBitNumber+edx] +iglobal +bcj_kMaskToBitNumber db 24,16,8,8,0,0,0,0 +endg +@@: + sub eax, [ebx+bcj_decoder.nowPos] + add eax, [ebx+streamInfo.bufDataLen] + sub eax, edi + sub eax, 4 + add eax, [ebx+streamInfo.bufPtr] + cmp cl, 24 + jz @f + push eax + shr eax, cl + add al, 1 + cmp al, 2 + pop eax + jae @f + mov edx, 0x100 + shl edx, cl + sub edx, 1 + xor eax, edx + jmp @b +@@: + pop ecx + shl eax, 7 + sar eax, 7 + sub ebp, 4 + jb .finalize_dword + stosd + jmp .mainloop +.miss2: + or [ebx+bcj_decoder.prevMask], 10h +.miss: + or [ebx+bcj_decoder.prevMask], 1 + cmp [ebx+bcj_decoder.tempSize], 0 + jz @f + lea esi, [ebx+bcj_decoder.tempDword] + pop dword [esi] + mov ecx, [ebx+bcj_decoder.tempSize] + jmp .mainloop +@@: + pop eax + sub esi, 4 + add ecx, 4 + jmp .mainloop +.finalize_dword: + add ebp, 4 + mov [ebx+bcj_decoder.numRest], 4 +@@: + dec ebp + js .save_dword + stosb + dec [ebx+bcj_decoder.numRest] + shr eax, 8 + jmp @b +.save_dword: + mov [ebx+bcj_decoder.dwordRest], eax +.mainloopdone: + mov eax, [ebx+bcj_decoder.prevPos] + test eax, eax + jz .noprev + sub eax, edi + mov [ebx+bcj_decoder.prevPos], eax +.noprev: + mov eax, [ebx+bcj_decoder.inStream] + sub esi, [eax+streamInfo.bufPtr] + mov [ebx+bcj_decoder.inPtr], esi + mov [ebx+bcj_decoder.inSize], ecx + popad + ret + +.refill1: + cmp ecx, -1 + jz .refill0 + lodsb + cmp ecx, -4 + jnz @f + mov ecx, [ebx+bcj_decoder.inStream] + mov esi, [ecx+streamInfo.bufPtr] + mov ecx, [ecx+streamInfo.bufDataLen] +@@: + jmp .filled2 +.refill0: + mov eax, [ebx+bcj_decoder.inStream] + call fillBuf + mov esi, [eax+streamInfo.bufPtr] + mov ecx, [eax+streamInfo.bufDataLen] + sub ecx, 1 + js return.err + jmp .filled1 + +.nopos: + mov eax, [ebx+bcj_decoder.inStream] + cmp dword [eax+streamInfo.fullSize+4], 0 + jnz .hasdata + push ecx + add ecx, dword [eax+streamInfo.fullSize] + pop ecx + jc .hasdata + add ecx, 4 + jmp .mainloop +.hasdata: + mov [ebx+bcj_decoder.tempSize], ecx + push 0 + push edi + lea edi, [esp+4] + add ecx, 4 + rep movsb + sub esi, ebx + sub esi, 1 + cmp esi, bcj_decoder.tempDword+4 + jbe @f + call fillBuf +@@: + mov esi, [eax+streamInfo.bufPtr] + mov ecx, [ebx+bcj_decoder.tempSize] + neg ecx + rep movsb + pop edi + mov ecx, [eax+streamInfo.bufDataLen] + add ecx, [ebx+bcj_decoder.tempSize] + cmp [ebx+bcj_decoder.tempSize], -4 + jnz .posok + and [ebx+bcj_decoder.tempSize], 0 + jmp .posok +.nopos2: + mov eax, [ebx+bcj_decoder.inStream] + add ecx, 4 + jmp .hasdata + +virtual at 0 +bcj2_decoder: +.outStream rb streamInfo.size +.mainInStream dd ? +.callStream dd ? +.jumpStream dd ? +.rangeDecoder dd ? +.dwordRest dd ? +.prevByte db ? +.numRest db ? +.bInited db ? + rb 1 +.inPtr dd ? +.inSize dd ? +.callPtr dd ? +.jumpPtr dd ? +.callSize dd ? +.jumpSize dd ? +.rangeDecPtr dd ? +.rangeDecSize dd ? +.nowPos dd ? +.range dd ? +.code dd ? +.statusE9Decoder dd ? +.statusJccDecoder dd ? +.statusE8Decoder rd 256 +.size = $ +end virtual + +bcj2_get_buf_size: + mov eax, bcj2_decoder.size + mov edx, 0x4000 + ret + +bcj2_init_decoder: + mov [ebp+streamInfo.fillBuf], bcj2_fillBuf + mov eax, lzma_decoder.kBitModelTotal/2 + mov ecx, 256+1+1 + lea edi, [ebp+bcj2_decoder.statusE9Decoder] + rep stosd + mov dword [ebp+bcj2_decoder.prevByte], ecx + mov [ebp+bcj2_decoder.inSize], ecx + mov [ebp+bcj2_decoder.callSize], ecx + mov [ebp+bcj2_decoder.jumpSize], ecx + mov [ebp+bcj2_decoder.rangeDecSize], ecx + mov [ebp+bcj2_decoder.nowPos], ecx + ret + +bcj2_fillBuf.init: + mov eax, [eax+bcj2_decoder.rangeDecoder] + call fillBuf + mov edx, [eax+streamInfo.bufDataLen] + sub edx, 5 + jb return.err + mov [ebp+bcj2_decoder.rangeDecSize], edx + mov edx, [eax+streamInfo.bufPtr] + add edx, 5 + mov [ebp+bcj2_decoder.rangeDecPtr], edx + mov edx, [edx-4] + bswap edx + mov [ebp+bcj2_decoder.code], edx + or [ebp+bcj2_decoder.range], -1 + mov [ebp+bcj2_decoder.bInited], 1 + mov eax, ebp + jmp bcj2_fillBuf.inited + +bcj2_fillBuf: + mov ebp, eax + cmp [eax+bcj2_decoder.bInited], 0 + jz .init +.inited: + add [eax+bcj2_decoder.nowPos], ecx + mov esi, [eax+bcj2_decoder.inPtr] +@@: + cmp [ebp+bcj2_decoder.numRest], 0 + jz .mainloop + sub ecx, 1 + js .mainloopdone + dec [ebp+bcj2_decoder.numRest] + mov eax, [ebp+bcj2_decoder.dwordRest] + stosb + mov [ebp+bcj2_decoder.prevByte], al + shr eax, 8 + mov [ebp+bcj2_decoder.dwordRest], eax + jmp @b +.mainloop: + sub ecx, 1 + js .mainloopdone + sub [ebp+bcj2_decoder.inSize], 1 + js .refill1 +.filled1: + lodsb + stosb + cmp al, 0xE8 + jz .e8 + cmp al, 0xE9 + jz .e9 + cmp [ebp+bcj2_decoder.prevByte], 0xF + mov [ebp+bcj2_decoder.prevByte], al + jnz .mainloop + and al, 0xF0 + cmp al, 0x80 + jnz .mainloop +.jcc: + lea eax, [ebp+bcj2_decoder.statusJccDecoder] + call .RangeDecoderBitDecode + jnc .mainloop + jmp .getptrj +.e8: + movzx eax, al + xchg al, [ebp+bcj2_decoder.prevByte] + lea eax, [ebp+bcj2_decoder.statusE8Decoder+eax*4] + call .RangeDecoderBitDecode + jnc .mainloop + lea eax, [ebp+bcj2_decoder.callPtr] + jmp .getptr +.e9: + mov [ebp+bcj2_decoder.prevByte], al + lea eax, [ebp+bcj2_decoder.statusE9Decoder] + call .RangeDecoderBitDecode + jnc .mainloop +.getptrj: + lea eax, [ebp+bcj2_decoder.jumpPtr] +.getptr: + sub dword [eax+8], 4 + js .refill2 +.filled2: + add dword [eax], 4 + mov eax, [eax] + mov eax, [eax-4] + bswap eax + sub eax, [ebp+bcj2_decoder.nowPos] + add eax, [ebp+streamInfo.bufDataLen] + sub eax, edi + sub eax, 4 + add eax, [ebp+streamInfo.bufPtr] + sub ecx, 4 + jb .finalize_dword + stosd + shr eax, 24 + mov [ebp+bcj2_decoder.prevByte], al + jmp .mainloop +.finalize_dword: + add ecx, 4 + mov [ebp+bcj2_decoder.numRest], 4 +@@: + dec ecx + js .save_dword + stosb + dec [ebp+bcj2_decoder.numRest] + shr eax, 8 + jmp @b +.save_dword: + mov [ebp+bcj2_decoder.dwordRest], eax +.mainloopdone: + mov [ebp+bcj2_decoder.inPtr], esi + popad + ret + +.refill1: + mov eax, [ebp+bcj2_decoder.mainInStream] + call fillBuf + mov edx, [eax+streamInfo.bufDataLen] + dec edx + js return.err + mov [ebp+bcj2_decoder.inSize], edx + mov esi, [eax+streamInfo.bufPtr] + jmp .filled1 + +.refill2: + push eax + mov eax, [eax-bcj2_decoder.callPtr+bcj2_decoder.callStream] + call fillBuf + mov edx, [eax+streamInfo.bufDataLen] + sub edx, 4 + js return.err + push [eax+streamInfo.bufPtr] + mov eax, [esp+4] + pop dword [eax] + pop eax + mov [eax+8], edx + jmp .filled2 + +.refill3: + push eax + mov eax, [ebp+bcj2_decoder.rangeDecoder] + call fillBuf + mov edx, [eax+streamInfo.bufDataLen] + dec edx + js return.err + mov [ebp+bcj2_decoder.rangeDecSize], edx + mov edx, [eax+streamInfo.bufPtr] + mov [ebp+bcj2_decoder.rangeDecPtr], edx + pop eax + jmp .filled3 + +.RangeDecoderBitDecode: +; in: eax->prob +; out: CF=bit; destroys eax,edx + mov edx, [ebp+bcj2_decoder.range] + shr edx, lzma_decoder.kNumBitModelTotalBits + imul edx, [eax] + cmp [ebp+bcj2_decoder.code], edx + jae .ae + mov [ebp+bcj2_decoder.range], edx + mov edx, lzma_decoder.kBitModelTotal + sub edx, [eax] + shr edx, lzma_decoder.kNumMoveBits + add [eax], edx + clc +.n: + lahf + cmp [ebp+bcj2_decoder.range], lzma_decoder.kTopValue + jae @f + shl [ebp+bcj2_decoder.range], 8 + shl [ebp+bcj2_decoder.code], 8 + dec [ebp+bcj2_decoder.rangeDecSize] + js .refill3 +.filled3: + mov edx, [ebp+bcj2_decoder.rangeDecPtr] + mov al, [edx] + add edx, 1 + mov [ebp+bcj2_decoder.rangeDecPtr], edx + mov byte [ebp+bcj2_decoder.code], al +@@: + sahf + ret +.ae: + sub [ebp+bcj2_decoder.range], edx + sub [ebp+bcj2_decoder.code], edx + mov edx, [eax] + shr edx, lzma_decoder.kNumMoveBits + sub [eax], edx + stc + jmp .n diff --git a/programs/fs/kfar/trunk/kfar_arc/aes.inc b/programs/fs/kfar/trunk/kfar_arc/aes.inc new file mode 100644 index 0000000000..58adb5ad61 --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/aes.inc @@ -0,0 +1,274 @@ +; Implementation of AES crypto algorithm. +; Buffer size is 0x10 bytes (128 bits), key size is not fixed. +; Written by diamond in 2007. +uglobal +aes.pow_table rb 256 ; pow[a] = 3^a +aes.log_table rb 256 ; log[3^a] = a +aes.sbox rb 256 ; ShiftBytes(a) +aes.sbox_rev rb 256 ; ShiftBytes^{-1}(a) +aes.mctable rd 256 ; MixColumns(ShiftBytes(a,0,0,0)) +aes.mcrtable rd 256 ; MixColumns^{-1}(a,0,0,0) +endg + +init_aes: +; Byte values in SubBytes transform are interpreted as items of +; GF(2^8) \cong F_2[x]/(x^8+x^4+x^3+x+1)F_2[x]. +; x+1 is primitive item in this field. + xor ebx, ebx + push 1 + pop eax +.1: + mov [aes.pow_table+ebx], al + mov [aes.log_table+eax], bl +; Multiplication by x+1... + mov cl, al ; save value +; ...multiply by x with mod (x^8+x^4+x^3+x+1) = 0x11B... + add al, al + jnc @f + xor al, 0x1B +@@: +; ...and add operand + xor al, cl + inc bl + jnz .1 +; generate table for SubBytes transform + mov [aes.sbox+0], 0x63 + mov [aes.sbox_rev+0x63], bl + inc ebx +.2: +; calculate inverse in GF(2^8) + mov al, [aes.log_table+ebx] + xor al, 0xFF ; equivalent to "al = 0xFF - al" + mov cl, [aes.pow_table+eax] +; linear transform of byte as vector over F_2 + mov al, cl + rol cl, 1 + xor al, cl + rol cl, 1 + xor al, cl + rol cl, 1 + xor al, cl + rol cl, 1 + xor al, cl + xor al, 0x63 + mov [aes.sbox+ebx], al + mov [aes.sbox_rev+eax], bl + inc bl + jnz .2 +; generate table for SubBytes + MixColumn transforms +.3: + mov al, [aes.sbox+ebx] ; SubBytes transform + mov cl, al + add cl, cl + jnc @f + xor cl, 0x1B +@@: + mov byte [aes.mctable+ebx*4], cl ; low byte of MixColumn(a,0,0,0) + mov byte [aes.mctable+ebx*4+1], al + mov byte [aes.mctable+ebx*4+2], al + xor cl, al + mov byte [aes.mctable+ebx*4+3], cl ; high byte of MixColumn(a,0,0,0) + inc bl + jnz .3 +; generate table for reverse MixColumn transform + mov dword [aes.mcrtable+0], ebx + inc ebx +.4: +; log_table[9]=0xC7, log_table[0xB]=0x68, log_table[0xD]=0xEE, log_table[0xE]=0xDF + mov cl, [aes.log_table+ebx] + mov al, cl + add al, 0xDF + adc al, 0 + mov al, [aes.pow_table+eax] + mov byte [aes.mcrtable+ebx*4], al + mov al, cl + add al, 0xC7 + adc al, 0 + mov al, [aes.pow_table+eax] + mov byte [aes.mcrtable+ebx*4+1], al + mov al, cl + add al, 0xEE + adc al, 0 + mov al, [aes.pow_table+eax] + mov byte [aes.mcrtable+ebx*4+2], al + mov al, cl + add al, 0x68 + adc al, 0 + mov al, [aes.pow_table+eax] + mov byte [aes.mcrtable+ebx*4+3], al + inc bl + jnz .4 + ret + +aes_setkey: +; in: esi->key, edx=key size in dwords, edi->AES data struc + lea eax, [edx+6] ; calc number of rounds (buffer size=4) + stosd + shl eax, 4 + lea ebx, [edi+eax+16] + mov ecx, edx + rep movsd + push ebx + mov bl, 1 +.0: + push 4 + pop ecx +@@: + movzx esi, byte [edi-5+ecx] + mov al, [aes.sbox+esi] + rol eax, 8 + loop @b + ror eax, 16 + mov esi, edx + neg esi + xor eax, [edi+esi*4] + xor al, bl + add bl, bl + jnc @f + xor bl, 0x1B +@@: + stosd + lea ecx, [edx-1] +.1: + cmp edi, [esp] + jz .ret + cmp edx, 8 + jnz @f + cmp ecx, 4 + jnz @f + push eax + movzx eax, al + mov al, [aes.sbox+eax] + mov [esp], al + mov al, byte [esp+1] + mov al, [aes.sbox+eax] + mov [esp+1], al + mov al, byte [esp+2] + mov al, [aes.sbox+eax] + mov [esp+2], al + mov al, byte [esp+3] + mov al, [aes.sbox+eax] + mov [esp+3], al + pop eax +@@: + xor eax, [edi+esi*4] + stosd + loop .1 + cmp edi, [esp] + jnz .0 +.ret: + pop eax + ret + +aes_decode: +; in: esi->in, ebx->out, edi->AES state + push ebx ebp + push dword [esi+12] + push dword [esi+8] + push dword [esi+4] + push dword [esi] + mov esi, esp +; reverse final round + mov ebp, [edi] ; number of rounds + mov ecx, ebp + shl ecx, 4 + lea edi, [edi+ecx+4] ; edi->last round key +; load buffer into registers + mov eax, [esi] + mov ebx, [esi+4] + mov ecx, [esi+8] + mov edx, [esi+12] +; (AddRoundKey) + xor eax, [edi] + xor ebx, [edi+4] + xor ecx, [edi+8] + xor edx, [edi+12] +; (ShiftRows) +.loop0: + xchg ch, dh + xchg bh, ch + xchg ah, bh + rol eax, 16 + rol ebx, 16 + rol ecx, 16 + rol edx, 16 + xchg al, cl + xchg bl, dl + xchg ah, bh + xchg bh, ch + xchg ch, dh + rol eax, 16 + rol ebx, 16 + rol ecx, 16 + rol edx, 16 +; (SubBytes) + mov [esi], eax + mov [esi+4], ebx + mov [esi+8], ecx + mov [esi+12], edx + mov ecx, 16 +@@: + movzx eax, byte [esi] + mov al, [aes.sbox_rev+eax] + mov byte [esi], al + add esi, 1 + sub ecx, 1 + jnz @b + sub esi, 16 + sub edi, 16 +; reverse normal rounds + sub ebp, 1 + jz .done + mov eax, [esi] + mov ebx, [esi+4] + mov ecx, [esi+8] + mov edx, [esi+12] + push esi edi +; (AddRoundKey) + xor eax, [edi] + xor ebx, [edi+4] + xor ecx, [edi+8] + xor edx, [edi+12] +; (MixColumns) +macro mix_reg reg { + movzx esi, reg#l + mov edi, [aes.mcrtable+esi*4] + movzx esi, reg#h + rol e#reg#x, 16 + mov esi, [aes.mcrtable+esi*4] + rol esi, 8 + xor edi, esi + movzx esi, reg#l + mov esi, [aes.mcrtable+esi*4] + rol esi, 16 + xor edi, esi + movzx esi, reg#h + mov esi, [aes.mcrtable+esi*4] + ror esi, 8 + xor edi, esi + mov e#reg#x, edi +} + mix_reg a + mix_reg b + mix_reg c + mix_reg d +purge mix_reg + pop edi esi + jmp .loop0 +.done: +; (AddRoundKey) + mov esi, [esp+20] + pop eax + xor eax, [edi] + mov [esi], eax + pop eax + xor eax, [edi+4] + mov [esi+4], eax + pop eax + xor eax, [edi+8] + mov [esi+8], eax + pop eax + xor eax, [edi+12] + mov [esi+12], eax + pop ebp ebx + ret diff --git a/programs/fs/kfar/trunk/kfar_arc/crc.inc b/programs/fs/kfar/trunk/kfar_arc/crc.inc new file mode 100644 index 0000000000..5048394d64 --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/crc.inc @@ -0,0 +1,32 @@ +init_crc_table: + xor edx, edx + mov edi, crc_table +.1: + mov ecx, 8 + mov eax, edx +.2: + shr eax, 1 + jnc @f + xor eax, 0xEDB88320 +@@: + loop .2 + stosd + inc dl + jnz .1 + ret + +crc: +; in: ecx=size, esi->buffer +; out: eax=crc + or eax, -1 + jecxz .end +.loop: + movzx edx, al + xor dl, byte [esi] + inc esi + shr eax, 8 + xor eax, [crc_table+edx*4] + loop .loop +.end: + xor eax, -1 + ret diff --git a/programs/fs/kfar/trunk/kfar_arc/kfar_arc.asm b/programs/fs/kfar/trunk/kfar_arc/kfar_arc.asm new file mode 100644 index 0000000000..6a289a21da --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/kfar_arc.asm @@ -0,0 +1,1075 @@ +; +; project name: KFar_Arc - plugin for KFar, which supports various archives +; target platform: KolibriOS +; compiler: FASM 1.67.14 +; version: 0.1 +; last update: 2007-07-11 (Jul 11, 2007) +; minimal KFar version: 0.4 +; minimal kernel: no limit +; +; author: Diamond +; email: diamondz@land.ru +; web: http://diamondz.land.ru +; + +; standard start of Kolibri dynamic library +format MS COFF +public EXPORTS + +section '.flat' code readable align 16 + +; include auxiliary procedures +include 'kglobals.inc' ; iglobal/uglobal +include 'lang.inc' ; define language for localized strings +include 'crc.inc' ; CRC32 calculation +include 'sha256.inc' ; SHA-256 hash algorithm +include 'aes.inc' ; AES crypto algorithm +; include main code for archives loading +include '7z.inc' ; *.7z +include 'lzma.inc' ; LZMA-decoder for *.7z +include 'ppmd.inc' ; PPMD-decoder for *.7z +include '7zbranch.inc' ; branch filters for *.7z +include '7zaes.inc' ; AES cryptor for *.7z + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;; Interface for KFar ;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +virtual at 0 +kfar_info_struc: +.lStructSize dd ? +.kfar_ver dd ? +.open dd ? +.read dd ? +.write dd ? +.seek dd ? +.flush dd ? +.filesize dd ? +.close dd ? +.pgalloc dd ? +.pgrealloc dd ? +.pgfree dd ? +.getfreemem dd ? +.pgalloc2 dd ? +.pgrealloc2 dd ? +.pgfree2 dd ? +.menu dd ? +.menu_centered_in dd ? +.DialogBox dd ? +.SayErr dd ? +.Message dd ? +.cur_console_size dd ? +end virtual + +; int __stdcall plugin_load(kfar_info* info); +; Initialization of plugin + Save used KFar functions. +plugin_load: + mov eax, [esp+4] + mov [kfar_info], eax + push [eax+kfar_info_struc.read] + pop [read] + push [eax+kfar_info_struc.seek] + pop [seek] + push [eax+kfar_info_struc.close] + pop [close] + lea esi, [eax+kfar_info_struc.DialogBox] + mov edi, DialogBox + movsd + movsd + movsd + movsd + lea esi, [eax+kfar_info_struc.pgalloc] + mov edi, pgalloc + movsd + movsd + movsd + movsd + call init_crc_table + call init_aes + call init_ppmd + xor eax, eax ; success + ret 4 + +; HANDLE __stdcall OpenFilePlugin(HANDLE basefile, const char* name, +; const void* attr, const void* data, int datasize); +; This function is called when user presses Enter (or Ctrl+PgDn) on file. +; Plugin tests whether given file is of supported type +; and if so, loads information and returns +; handle to be used in subsequent calls to ReadFolder, SetFolder and so on. +OpenFilePlugin: + mov [bPasswordDefined], 0 + mov esi, [esp+16] + mov ebp, [esp+4] +; test for 7z archive + cmp dword [esp+20], 20h ; minimal size of 7z archive is 20h bytes + jb .no_7z + cmp word [esi], '7z' ; signature, part 1 + jnz .no_7z + cmp dword [esi+2], 0x1C27AFBC ; signature, part 2 + jnz .no_7z + call open_7z + ret 20 +.no_7z: + xor eax, eax + ret 20 + +; Handle of plugin in kfar_arc is as follow: +virtual at 0 +handle_common: +.type dd ? +.root.subfolders dd ? +.root.subfolders.end dd ? +.root.subfiles dd ? +.root.subfiles.end dd ? +.root.NumSubItems dd ? +; ... some plugin-specific data follows ... +end virtual + +; and for each archive item there is one file info structure, which begins as follow: +virtual at 0 +file_common: +.fullname dd ? ; pointer to cp866 string +.name dd ? ; name without path (end of .fullname) +.namelen dd ? ; strlen(.name) +.bIsDirectory db ? +.bPseudoFolder db ? + rb 2 +.parent dd ? ; pointer to parent directory record +.subfolders dd ? ; head of L2-list of subfolders [for folders] +.subfolders.end dd ? +.subfiles dd ? ; head of L2-list of files [for folders] +.subfiles.end dd ? +.NumSubItems dd ? +.next dd ? ; next item in list of subfolders/files +.prev dd ? ; previous item in list of subfolders/files +end virtual + +; void __stdcall ClosePlugin(HANDLE hPlugin); +; This function frees all resources allocated in OpenFilePlugin. +ClosePlugin: + mov eax, [esp+4] ; get hPlugin + mov eax, [eax] ; hPlugin is pointer to internal data structure + ; first dword is archive type (type_xxx constants) + dec eax ; types start from 1 + jmp dword [ClosePluginTable+eax*4] + +; int __stdcall ReadFolder(HANDLE hPlugin, +; unsigned dirinfo_start, unsigned dirinfo_size, void* dirdata); +ReadFolder: + mov eax, [esp+4] + mov eax, [eax] + dec eax + jmp dword [ReadFolderTable+eax*4] + +; bool __stdcall SetFolder(HANDLE hPlugin, +; const char* relative_path, const char* absolute_path); +SetFolder: + mov eax, [esp+4] + mov eax, [eax] + dec eax + jmp dword [SetFolderTable+eax*4] + +; void __stdcall GetFiles(HANDLE hPlugin, int NumItems, void* items[], +; void* addfile, void* adddir); +; bool __stdcall addfile(const char* name, void* bdfe_info, HANDLE hFile); +; bool __stdcall adddir(const char* name, void* bdfe_info); +GetFiles: + mov ebp, [esp+4] + mov eax, [ebp] + dec eax + jmp dword [GetFilesTable+eax*4] + +; void __stdcall GetOpenPluginInfo(HANDLE hPlugin, OpenPluginInfo* info); +GetOpenPluginInfo: + mov eax, [esp+8] ; get info ptr + mov byte [eax], 3 ; flags: add non-existing '..' entry automatically + ; use GetFiles for copying + ret 8 + +; int __stdcall getattr(HANDLE hPlugin, const char* filename, void* info); +mygetattr: + call lookup_file_name + test eax, eax + jz @f + mov edx, [ebp] + dec edx + mov edi, [esp+12] ; info ptr + call dword [getattrTable+edx*4] + xor eax, eax + ret 12 +@@: + mov al, 5 ; ERROR_FILE_NOT_FOUND + ret 12 + +; HANDLE __stdcall open(HANDLE hPlugin, const char* filename, int mode); +myopen: + call lookup_file_name + test eax, eax + jz @f + mov edx, [ebp] + dec edx + mov edi, [esp+12] ; mode + call dword [openTable+edx*4] +@@: + ret 12 + +; unsigned __stdcall read(HANDLE hFile, void* buf, unsigned size); +myread: + mov ebx, [esp+4] + mov eax, [ebx] + jmp dword [readTable+eax*4] + +; void __stdcall setpos(HANDLE hFile, __int64 pos); +mysetpos: + mov ebx, [esp+4] + mov eax, [ebx] + jmp dword [setposTable+eax*4] + +; void __stdcall close(HANDLE hFile); +myclose: + mov ebx, [esp+4] + mov eax, [ebx] + jmp dword [closeTable+eax*4] + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;; Auxiliary procedures ;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; return.err and return.clear are labels to jmp if something is invalid +; the caller must previously define [_esp], [_ebp] and [error_proc], [clear_proc] +return.err: + mov esp, [_esp] + mov ebp, [_ebp] + jmp [error_proc] +return.clear: + mov esp, [_esp] + mov ebp, [_ebp] + jmp [clear_proc] + +; data for following routine +iglobal +align 4 +_24 dd 24 +_60 dd 60 +_10000000 dd 10000000 +days400year dd 365*400+100-4+1 +days100year dd 365*100+25-1 +days4year dd 365*4+1 +days1year dd 365 +months dd 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +months2 dd 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +_400 dd 400 +_100 dd 100 +endg + +; Convert QWORD FILETIME to BDFE format. +ntfs_datetime_to_bdfe: +; edx:eax = number of 100-nanosecond intervals since January 1, 1601, in UTC + push eax + mov eax, edx + xor edx, edx + div [_10000000] + xchg eax, [esp] + div [_10000000] + pop edx +; edx:eax = number of seconds since January 1, 1601 + push eax + mov eax, edx + xor edx, edx + div [_60] + xchg eax, [esp] + div [_60] + mov [edi], dl + pop edx +; edx:eax = number of minutes + div [_60] + mov [edi+1], dl +; eax = number of hours (note that 2^64/(10^7*60*60) < 2^32) + xor edx, edx + div [_24] + mov [edi+2], dl + mov [edi+3], byte 0 +; eax = number of days since January 1, 1601 + xor edx, edx + div [days400year] + imul eax, 400 + add eax, 1601 + mov [edi+6], ax + mov eax, edx + xor edx, edx + div [days100year] + cmp al, 4 + jnz @f + dec eax + add edx, [days100year] +@@: + imul eax, 100 + add [edi+6], ax + mov eax, edx + xor edx, edx + div [days4year] + shl eax, 2 + add [edi+6], ax + mov eax, edx + xor edx, edx + div [days1year] + cmp al, 4 + jnz @f + dec eax + add edx, [days1year] +@@: + add [edi+6], ax + push esi edx + mov esi, months + movzx eax, word [edi+6] + test al, 3 + jnz .noleap + xor edx, edx + push eax + div [_400] + pop eax + test edx, edx + jz .leap + xor edx, edx + div [_100] + test edx, edx + jz .noleap +.leap: + mov esi, months2 +.noleap: + pop edx + xor eax, eax + inc eax +@@: + sub edx, [esi] + jb @f + add esi, 4 + inc eax + jmp @b +@@: + add edx, [esi] + pop esi + inc edx + mov [edi+4], dl + mov [edi+5], al + add edi, 8 + ret + +; By given array of files information, initialize links between them +; ("[folder] contains [item]" relations). +; Information structure must be compatible with 'file_common'. +; Size of information structure is in [esp+4]. +init_file_links: +; in: edx->file infos, ebx = number of files, [esp+4] = size, +; edi->{dd root.subfolders, dd root.subfolders.end, +; dd root.subfiles, dd root.subfiles.end, dd root.NumItems} + xor eax, eax + mov [.free], eax + push edi + stosd + stosd + stosd + stosd + stosd + pop edi +; Loop through all files +.mainloop: + dec ebx + js .mainloopdone +; Parse file name +; esi->current character in name +; dword [esp] = start of current component in file name +; ecx->{dd curdir.subfolders, dd curdir.subfolders.end, +; dd curdir.subfiles, dd curdir.subfiles.end} + mov esi, [edx+file_common.fullname] + mov ecx, edi +.parseloop: + push esi +.parsename: + lodsb + test al, al + jz @f + cmp al, '/' + jnz .parsename +@@: +; we have found next component of current name; look for it in current directory + sub esi, [esp] + dec esi ; esi = strlen(component) + cmp esi, 259 + jbe @f + push ContinueBtn + push 1 + push aNameTooLong_ptr + push 1 + call [SayErr] + jmp return.clear +@@: + push ecx + mov eax, [ecx] ; eax->subfolders list + mov ecx, esi +.scansubfolders: + test eax, eax + jz .nofolder + add eax, [hOut] + cmp [eax+file_common.namelen], ecx + jnz .scancont + mov esi, [esp+4] + push ecx edi + mov edi, [eax+file_common.name] + repz cmpsb + pop edi ecx + jz .subfound +.scancont: + mov eax, [eax+file_common.next] + jmp .scansubfolders +.subfound: +; found subfolder, set it as current and continue parsing name + add [esp+4], ecx + pop ecx + lea ecx, [eax+file_common.subfolders] + pop esi + lodsb + test al, al + jnz .parseloop +; that was the last component of the name, and we have found subfolder +; so found subfolder is a virtual subfolder and must be replaced with current +; name + mov eax, [ecx-file_common.subfolders+file_common.namelen] + mov [edx+file_common.namelen], eax + sub esi, eax + dec esi + mov [edx+file_common.name], esi + sub edx, [hOut] ; convert pointer to relative +; replace item in L2-list + mov eax, [ecx-file_common.subfolders+file_common.prev] + test eax, eax + jnz .1 + mov eax, [ecx-file_common.subfolders+file_common.parent] + sub eax, file_common.next - file_common.subfolders + jnc .1 + lea eax, [edi-file_common.next] + jmp .2 +.1: + add eax, [hOut] +.2: + mov [eax+file_common.next], edx + mov eax, [ecx-file_common.subfolders+file_common.next] + test eax, eax + jnz .3 + mov eax, [ecx-file_common.subfolders+file_common.parent] + sub eax, file_common.prev - file_common.subfolders.end + jnc .3 + lea eax, [edi-file_common.prev+4] + jmp .4 +.3: + add eax, [hOut] +.4: + mov [eax+file_common.prev], edx +; correct parent links in childrens + mov eax, [ecx] +@@: + test eax, eax + jz @f + add eax, [hOut] + mov [eax+file_common.parent], edx + mov eax, [eax+file_common.next] + jmp @b +@@: + mov eax, [ecx+8] +@@: + test eax, eax + jz @f + add eax, [hOut] + mov [eax+file_common.parent], edx + mov eax, [eax+file_common.next] + jmp @b +@@: + add edx, [hOut] +; set children links + mov eax, [ecx] + mov [edx+file_common.subfolders], eax + mov eax, [ecx+4] + mov [edx+file_common.subfolders.end], eax + mov eax, [ecx+8] + mov [edx+file_common.subfiles], eax + mov eax, [ecx+12] + mov [edx+file_common.subfiles.end], eax + mov eax, [ecx+16] + mov [edx+file_common.NumSubItems], eax +; set prev/next links + mov eax, [ecx-file_common.subfolders+file_common.next] + mov [edx+file_common.next], eax + mov eax, [ecx-file_common.subfolders+file_common.prev] + mov [edx+file_common.prev], eax +; add old item to list of free items +uglobal +align 4 +init_file_links.free dd ? +endg + sub ecx, file_common.subfolders + mov eax, [.free] + mov [ecx], eax + sub ecx, [hOut] + mov [.free], ecx + jmp .mainloopcont +.nofolder: + mov eax, edx + mov esi, [esp+4] + cmp byte [esi+ecx], 0 + jz .newitem +; the current item is as 'dir1/item1' and 'dir1' has not been found +; allocate virtual subfolder 'dir1' + mov eax, [init_file_links.free] + test eax, eax + jz .realloc + add eax, [hOut] + push dword [eax] + pop [init_file_links.free] + jmp .allocated +.realloc: +; there is no free space, so reallocate [hOut] block + mov eax, [hOut] + sub [esp], eax ; make pointers relative + sub edx, eax + sub edi, eax + push ecx + mov ecx, [hOut.allocated] + add ecx, [esp+12+4] + mov [hOut.allocated], ecx + push ecx + and ecx, 0xFFF + cmp ecx, [esp+16+4] + pop ecx + ja @f + push edx + mov edx, eax + call [pgrealloc] + pop edx + test eax, eax + jnz @f + mov ecx, [hOut] + call [pgfree] + mov esp, [_esp] + or eax, -1 + ret +@@: + pop ecx + mov [hOut], eax + add [esp], eax ; make pointers absolute + add edx, eax + add edi, eax + add eax, [hOut.allocated] + sub eax, [esp+8+4] +.allocated: +; eax -> new item + mov [eax+file_common.bIsDirectory], 1 + mov [eax+file_common.bPseudoFolder], 1 +.newitem: + mov [eax+file_common.namelen], ecx + pop ecx + pop esi +; ecx = parent item, eax = current item + mov [eax+file_common.name], esi + inc dword [ecx+16] ; new item in parent folder + push ecx +; add new item to end of L2-list + and [eax+file_common.next], 0 + cmp [eax+file_common.bIsDirectory], 0 + jnz @f + add ecx, 8 +@@: + push eax + sub eax, [hOut] + cmp dword [ecx], 0 + jnz @f + mov [ecx], eax +@@: + xchg eax, [ecx+4] + xchg eax, ecx + pop eax + mov [eax+file_common.prev], ecx + jecxz @f + add ecx, [hOut] + sub eax, [hOut] + mov [ecx+file_common.next], eax + add eax, [hOut] +@@: + pop ecx +; set parent link + and [eax+file_common.parent], 0 + cmp ecx, edi + jz @f + sub ecx, file_common.subfolders + sub ecx, [hOut] + mov [eax+file_common.parent], ecx +@@: +; set current directory to current item + lea ecx, [eax+file_common.subfolders] +; if that was not last component, continue parse name + add esi, [eax+file_common.namelen] + lodsb + test al, al + jnz .parseloop +.mainloopcont: +; continue main loop + add edx, [esp+4] + jmp .mainloop +.mainloopdone: +; Loop done. + ret 4 + +; This subroutine is called by getattr and open. +; This subroutine looks for file name and returns NULL or pointer to file info record. +lookup_file_name: + mov ebp, [esp+8] ; hPlugin + mov esi, [esp+12] ; filename + lea edi, [ebp+handle_common.root.subfolders] + xor eax, eax +; KFar operates with absolute names, skip first '/' + cmp byte [esi], '/' + jnz .notfound + inc esi +.mainloop: +; get next component of name + push -1 + pop ecx +@@: + inc ecx + cmp byte [esi+ecx], '/' + jz @f + cmp byte [esi+ecx], 0 + jnz @b +@@: +; esi->component, ecx=length +; scan for required item in subfolders list + push -1 + mov eax, [edi] ; .subfolders +.scan1: + test eax, eax + jz .notfound1 + add eax, ebp + cmp [eax+file_common.namelen], ecx + jnz .cont1 + push ecx esi edi + mov edi, [eax+file_common.name] + repz cmpsb + pop edi esi ecx + jz .found1 +.cont1: + mov eax, [eax+file_common.next] + jmp .scan1 +.notfound1: + pop edx +; if this is last component in file name, scan in subfiles list + cmp byte [esi+ecx], al + jnz .notfound + inc edx + jnz .notfound + mov eax, [edi+8] ; .subfiles + push edx + jmp .scan1 +.found1: + pop edi +; item is found, go to next component + lea edi, [eax+file_common.subfolders] + lea esi, [esi+ecx+1] + cmp byte [esi-1], 0 + jnz .mainloop +; this was the last component +.notfound: + ret + +; Memory streams handling. +; Archive handlers create memory stream for small files: +; size of which is not greater than (free RAM size)/4 and +; not greater than following constant... +;LIMIT_FOR_MEM_STREAM = 2*1024*1024 +; ...if it is defined. Now the definition is commented: +; if user has many physical memory, why not to use it? + +virtual at 0 +mem_stream: +.type dd ? ; type_mem_stream +.size dd ? +.pos dd ? +.buf: +end virtual + +; unsigned __stdcall read(ebx = HANDLE hFile, void* buf, unsigned size); +read_mem_stream: + mov eax, [esp+12] + mov ecx, [ebx+mem_stream.size] + sub ecx, [ebx+mem_stream.pos] + jnc @f + xor ecx, ecx +@@: + cmp eax, ecx + jb @f + mov eax, ecx +@@: + mov ecx, eax + lea esi, [ebx+mem_stream.buf] + add esi, [ebx+mem_stream.pos] + add [ebx+mem_stream.pos], eax + mov edi, [esp+8] + mov edx, ecx + shr ecx, 2 + rep movsd + mov ecx, edx + and ecx, 3 + rep movsb + ret 12 + +; void __stdcall setpos(ebx = HANDLE hFile, __int64 pos); +setpos_mem_stream: + mov eax, [esp+8] + mov [ebx+mem_stream.pos], eax + ret 12 + +; void __stdcall close(ebx = HANDLE hFile); +close_mem_stream: + mov ecx, ebx + call [pgfree] + ret 4 + +; Allocate handle for file +; esi -> handle table, ecx = size of handle +alloc_handle: +; Handle table is L2-list of allocated pages. +; Scan for free entry + mov edx, esi +@@: + mov edx, [edx] + cmp edx, esi + jz .alloc_new + mov eax, [edx+8] ; head of L1-list of free entries + test eax, eax ; has free entry? + jz @b +; we have found allocated page with free entry; allocate entry and return + inc dword [edx+12] ; number of busy entries + push dword [eax] + pop dword [edx+8] +.ret: + ret +.alloc_new: +; no free pages; get new page and initialize + push ecx + mov ecx, 0x1000 + call [pgalloc] + pop ecx + test eax, eax + jz .ret +; insert new page to start of L2-list + mov edx, [esi] + mov [eax], edx + mov [esi], eax + mov [eax+4], esi + mov [edx+4], eax + mov dword [eax+12], 1 ; 1 allocated entry +; initialize list of free entries + lea edx, [eax+16] + push edx ; save return value + add edx, ecx + mov [eax+8], edx + add eax, 0x1000 +@@: + mov esi, edx + add edx, ecx + mov [esi], edx + cmp edx, eax + jb @b + and dword [esi], 0 + pop eax + ret + +; Free handle allocated in previous procedure +; esi = handle +free_handle: + mov ecx, esi + and ecx, not 0xFFF ; get page +; add entry to head of L1-list of free entries + mov eax, [ecx+8] + mov [esi], eax + mov [ecx+8], esi + dec dword [ecx+12] ; decrement number of allocated entries + jnz .ret +; delete page from common L2-list + mov eax, [ecx] + mov edx, [ecx+4] + mov [eax+4], edx + mov [edx], eax +; free page + call [pgfree] +.ret: + ret + +; Ask user to enter password. +; Out: ZF set <=> user pressed Esc +; 'password_ansi', 'password_unicode', 'password_size' filled +query_password: + cmp [bPasswordDefined], 0 + jnz .ret + mov edi, password_data + mov eax, password_maxlen + stosd ; maximum length + xor eax, eax + stosd ; start of visible part + stosd ; position of cursor + stosb ; initial state: empty string + mov eax, [cur_console_size] + mov eax, [eax] ; get current console width + sub eax, 12 + mov edi, password_dlg + mov [edi+password_dlg.width-password_dlg], eax + dec eax + dec eax + mov [edi+password_dlg.width1-password_dlg], eax + mov [edi+password_dlg.width2-password_dlg], eax + push edi + call [DialogBox] + inc eax + jz .ret +; convert ANSI-cp866 to UNICODE string; also calculate 'password_size' + mov esi, password_ansi + mov edi, password_unicode + or [password_size], -1 +.cvt: + inc [password_size] + lodsb + mov ah, 0 +; 0x00-0x7F - trivial map + cmp al, 0x80 + jb .symb +; 0x80-0xAF -> 0x410-0x43F + cmp al, 0xB0 + jae @f + add ax, 0x410-0x80 + jmp .symb +@@: +; 0xE0-0xEF -> 0x440-0x44F + cmp al, 0xE0 + jb .unk + cmp al, 0xF0 + jae @f + add ax, 0x440-0xE0 + jmp .symb +@@: +; 0xF0 -> 0x401 +; 0xF1 -> 0x451 + cmp al, 'Ё' + jz .yo1 + cmp al, 'ё' + jz .yo2 +.unk: + mov al, '_' + jmp .symb +.yo1: + mov ax, 0x401 + jmp .symb +.yo2: + mov ax, 0x451 +.symb: + stosw + test al, al + jnz .cvt + inc [bPasswordDefined] ; clears ZF flag +.ret: + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;; Initialized data ;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; export table +align 4 +EXPORTS: + dd aVersion, 1 + dd aPluginLoad, plugin_load + dd aOpenFilePlugin,OpenFilePlugin + dd aClosePlugin, ClosePlugin + dd aReadFolder, ReadFolder + dd aSetFolder, SetFolder + dd aGetFiles, GetFiles + dd aGetOpenPluginInfo, GetOpenPluginInfo + dd aGetattr, mygetattr + dd aOpen, myopen + dd aRead, myread + dd aSetpos, mysetpos + dd aClose, myclose + dd 0 + +; exported names +aVersion db 'version',0 +aPluginLoad db 'plugin_load',0 +aOpenFilePlugin db 'OpenFilePlugin',0 +aClosePlugin db 'ClosePlugin',0 +aReadFolder db 'ReadFolder',0 +aSetFolder db 'SetFolder',0 +aGetFiles db 'GetFiles',0 +aGetOpenPluginInfo db 'GetOpenPluginInfo',0 +aGetattr db 'getattr',0 +aOpen db 'open',0 +aRead db 'read',0 +aSetpos db 'setpos',0 +aClose db 'close',0 + +; common strings +if lang eq ru +aContinue db 'Продолжить',0 +aCancel db 'Отмена',0 +aHeaderError db 'Ошибка в заголовке архива',0 +aReadError db 'Ошибка чтения',0 +aNoFreeRam db 'Недостаточно свободной оперативной памяти',0 +aEncodingProblem db 'Проблема с кодировкой',0 +aEncodingProblem_str db 'Имена некоторых файлов в архиве содержат символы,',0 +.2 db 'не представимые в кодировке cp866.',0 +.3 db 'Эти символы будут заменены на подчёркивания.',0 +aEnterPassword db 'Введите пароль:',0 +aEnterPasswordLen = $ - aEnterPassword - 1 +aEnterPasswordTitle db 'Ввод пароля',0 +aArchiveDataError db 'Ошибка в данных архива',0 +aArchiveDataErrorPass db 'Ошибка в данных архива или неверный пароль',0 +aChangePass db 'Ввести пароль',0 +aNameTooLong db 'Слишком длинное имя',0 +else +aContinue db 'Continue',0 +aCancel db 'Cancel',0 +aHeaderError db 'Invalid archive header',0 +aReadError db 'Read error',0 +aNoFreeRam db 'There is not enough of free RAM',0 +aEncodingProblem db 'Encoding problem',0 +aEncodingProblem_str db 'The names of some files in the archive contain',0 +.2 db 'characters which can not be represented in cp866.',0 +.3 db 'Such characters will be replaced to underscores.',0 +aEnterPassword db 'Enter password:',0 +aEnterPasswordLen = $ - aEnterPassword - 1 +aEnterPasswordTitle db 'Get password',0 +aArchiveDataError db 'Error in archive data',0 +aArchiveDataErrorPass db 'Error in archive data or incorrect password',0 +aChangePass db 'Enter password',0 +aNameTooLong db 'Name is too long',0 +end if + +; kfar_arc supports [hmm... will support...] many archive types. +; OpenFilePlugin looks for supported archive signature and gives control +; to concrete handler if found. +; Other functions just determine type of opened archive and jumps to corresponding handler. +type_mem_stream = 0 ; memory stream - for file handles (returned from 'open') +type_7z = 1 + +; archive functions (types start from type_7z) +align 4 +ClosePluginTable: + dd close_7z +ReadFolderTable: + dd ReadFolder_7z +SetFolderTable: + dd SetFolder_7z +GetFilesTable: + dd GetFiles_7z +getattrTable: + dd getattr_7z +openTable: + dd open_file_7z + +; file functions (types start from type_mem_stream) +readTable: + dd read_mem_stream + dd read_7z +setposTable: + dd setpos_mem_stream + dd setpos_7z +closeTable: + dd close_mem_stream + dd close_file_7z + +; pointers for SayErr and Message +ContinueBtn dd aContinue +HeaderError_ptr dd aHeaderError +aReadError_ptr dd aReadError +aNoFreeRam_ptr dd aNoFreeRam +aEncodingProblem_str_ptr: + dd aEncodingProblem_str + dd aEncodingProblem_str.2 + dd aEncodingProblem_str.3 +aNameTooLong_ptr dd aNameTooLong +aArchiveDataError_ptr dd aArchiveDataError +aArchiveDataErrorPass_ptr dd aArchiveDataErrorPass +CancelPassBtn dd aCancel + dd aChangePass + +; "enter password" dialog for KFar +password_dlg: + dd 1 ; use standard dialog colors + dd -1 ; center window by x + dd -1 ; center window by y +.width dd ? ; width (will be filled according to current console width) + dd 2 ; height + dd 4, 2 ; border size + dd aEnterPasswordTitle ; title + dd ? ; colors (will be set by KFar) + dd 0, 0 ; reserved for DlgProc + dd 2 ; 2 controls +; the string "enter password" + dd 1 ; type: static + dd 1,0 ; upper-left position +.width1 dd ?,0 ; bottom-right position + dd aEnterPassword ; data + dd 0 ; flags +; editbox for password + dd 3 ; type: edit + dd 1,1 ; upper-left position +.width2 dd ?,0 ; bottom-right position + dd password_data ; data + dd 2Ch ; flags + +IncludeIGlobals + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;; Uninitialized data ;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +section '.udata' data readable writable align 16 +kfar_info dd ? +crc_table rd 256 +_esp dd ? +_ebp dd ? +bufsize dd ? +bufptr dd ? +bufend dd ? +buffer rb 1024 +inStream dd ? +hOut dd ? +.allocated dd ? + +error_proc dd ? +clear_proc dd ? + +; import from kfar +read dd ? +seek dd ? +close dd ? +pgalloc dd ? +pgrealloc dd ? +pgfree dd ? +getfreemem dd ? +DialogBox dd ? +SayErr dd ? +Message dd ? +cur_console_size dd ? + +; data for editbox in kfar dialog +password_maxlen = 512 +password_data: +.maxlen dd ? +.pos dd ? +.start dd ? +password_ansi rb password_maxlen+1 +bPasswordDefined db ? + +; converted password +password_unicode rw password_maxlen+1 +password_size dd ? + +IncludeUGlobals + +bWasWarning db ? diff --git a/programs/fs/kfar/trunk/kfar_arc/kglobals.inc b/programs/fs/kfar/trunk/kfar_arc/kglobals.inc new file mode 100644 index 0000000000..75688d765d --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/kglobals.inc @@ -0,0 +1,50 @@ +;------------------------------------------------------------------ +; use "iglobal" for inserting initialized global data definitions. +;------------------------------------------------------------------ +macro iglobal { + IGlobals equ IGlobals, + macro __IGlobalBlock { } + +;------------------------------------------------------------- +; use 'uglobal' for inserting uninitialized global definitions. +; even when you define some data values, these variables +; will be stored as uninitialized data. +;------------------------------------------------------------- +macro uglobal { + UGlobals equ UGlobals, + macro __UGlobalBlock { } + +endg fix } ; Use endg for ending iglobal and uglobal blocks. + +macro IncludeIGlobals{ + macro IGlobals dummy,[n] \{ __IGlobalBlock + purge __IGlobalBlock \} + match I, IGlobals \{ I \} } + + +macro IncludeUGlobals{ + macro UGlobals dummy,[n] \{ + \common + \local begin, size + begin = $ + virtual at $ + \forward + __UGlobalBlock + purge __UGlobalBlock + \common + size = $ - begin + end virtual + rb size + \} + match U, UGlobals \{ U \} } + +macro IncludeAllGlobals { + IncludeIGlobals + IncludeUGlobals +} + +iglobal +endg + +uglobal +endg diff --git a/programs/fs/kfar/trunk/kfar_arc/lang.inc b/programs/fs/kfar/trunk/kfar_arc/lang.inc new file mode 100644 index 0000000000..30c0149bd9 --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/lang.inc @@ -0,0 +1 @@ +lang fix ru \ No newline at end of file diff --git a/programs/fs/kfar/trunk/kfar_arc/lzma.inc b/programs/fs/kfar/trunk/kfar_arc/lzma.inc new file mode 100644 index 0000000000..e3f822180b --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/lzma.inc @@ -0,0 +1,581 @@ +; LZMA decoder for *.7z archives. +; Based on C decoder in LZMA SDK (c) Igor Pavlov. +; Portions by Diamond, 2006, 2007. +lzma_decoder: +virtual at 0 +.outStream rb streamInfo.size +.inStream dd ? + +; RangeDecoder data +.inLen dd ? +.inPtr dd ? +.code dd ? +.range dd ? + +; parameters +.pb db ? ; pos state bits (0 - 4) +.lp db ? ; literal pos state bits (0 - 4) +.lc db ? ; literal context bits (0 - 8) +.previousByte db ? +.posStateMask dd ? ; (1 shl .pb)-1 +.literalPosMask dd ? ; (1 shl .lp)-1 + +; constants +.kNumPosBitsMax = 4 +.kNumPosStatesMax = (1 shl .kNumPosBitsMax) + +.kLenNumLowBits = 3 +.kLenNumLowSymbols = (1 shl .kLenNumLowBits) +.kLenNumMidBits = 3 +.kLenNumMidSymbols = (1 shl .kLenNumMidBits) +.kLenNumHighBits = 8 +.kLenNumHighSymbols = (1 shl .kLenNumHighBits) + +.LenChoice = 0 +.LenChoice2 = 1 +.LenLow = 2 +.LenMid = (.LenLow + (.kNumPosStatesMax shl .kLenNumLowBits)) +.LenHigh = (.LenMid + (.kNumPosStatesMax shl .kLenNumMidBits)) +.kNumLenProbs = (.LenHigh + .kLenNumHighSymbols) + +.kNumStates = 12 +.kNumLitStates = 7 +.kStartPosModelIndex = 4 +.kEndPosModelIndex = 14 +.kNumFullDistances = (1 shl (.kEndPosModelIndex/2)) +.kNumPosSlotBits = 6 +.kNumLenToPosStates = 4 +.kNumAlignBits = 4 +.kAlignTableSize = (1 shl .kNumAlignBits) +.kMatchMinLen = 2 + +.IsMatch = 0 +.IsRep = (.IsMatch + (.kNumStates shl .kNumPosBitsMax)) +.IsRepG0 = (.IsRep + .kNumStates) +.IsRepG1 = (.IsRepG0 + .kNumStates) +.IsRepG2 = (.IsRepG1 + .kNumStates) +.IsRep0Long = (.IsRepG2 + .kNumStates) +.PosSlot = (.IsRep0Long + (.kNumStates shl .kNumPosBitsMax)) +.SpecPos = (.PosSlot + (.kNumLenToPosStates shl .kNumPosSlotBits)) +.Align_ = (.SpecPos + .kNumFullDistances - .kEndPosModelIndex) +.Lencoder = (.Align_ + .kAlignTableSize) +.RepLencoder = (.Lencoder + .kNumLenProbs) +.Literal = (.RepLencoder + .kNumLenProbs) + +LZMA_BASE_SIZE = 1846 ; must be ==Literal +LZMA_LIT_SIZE = 768 + +.kNumTopBits = 24 +.kTopValue = (1 shl .kNumTopBits) + +.kNumBitModelTotalBits = 11 +.kBitModelTotal = (1 shl .kNumBitModelTotalBits) +.kNumMoveBits = 5 + +; variables +.continue dd ? +.ecx dd ? +.outEnd dd ? +.dictSize dd ? +.state dd ? +.rep0 dd ? +.rep1 dd ? +.rep2 dd ? +.rep3 dd ? +.p rd LZMA_BASE_SIZE +.basesize = $ +; rd LZMA_LIT_SIZE shl (.lc+.lp) +end virtual + +.fillBuf: + mov ebp, eax + mov ebx, [ebp+.state] + jecxz .nodata + add ecx, edi + mov [ebp+.outEnd], ecx + mov esi, [ebp+.inPtr] + jmp [ebp+.continue] +.nodata: + popad + ret +.start: + mov eax, [ebp+.inStream] + call fillBuf + mov esi, [eax+streamInfo.bufPtr] + mov eax, [eax+streamInfo.bufDataLen] + sub eax, 5 + jb return.err + mov [ebp+.inLen], eax + inc esi + lodsd + bswap eax + mov [ebp+.code], eax + or [ebp+.range], -1 +.main_loop: + cmp edi, [ebp+.outEnd] + jae .main_loop_done + mov edx, edi + and edx, [ebp+.posStateMask] + mov eax, ebx + shl eax, .kNumPosBitsMax + add eax, edx + lea eax, [ebp + .p + .IsMatch*4 + eax*4] + call .RangeDecoderBitDecode + jc .1 + movzx eax, [ebp+.previousByte] + mov ah, dl + and ah, byte [ebp+.literalPosMask] + mov cl, 8 + sub cl, [ebp+.lc] + shr eax, cl + imul eax, LZMA_LIT_SIZE*4 + lea eax, [ebp + eax + .p+.Literal*4] + cmp ebx, .kNumLitStates + jb .literal + xor edx, edx + sub edx, [ebp+.rep0] + mov dl, [edi + edx] + call .LzmaLiteralDecodeMatch + jmp @f +.literal: + call .LzmaLiteralDecode +@@: + mov [ebp+.previousByte], al + stosb + mov al, bl + cmp bl, 4 + jb @f + mov al, 3 + cmp bl, 10 + jb @f + mov al, 6 +@@: sub bl, al + jmp .main_loop +.1: + lea eax, [ebp + .p + .IsRep*4 + ebx*4] + call .RangeDecoderBitDecode + jnc .10 + lea eax, [ebp + .p + .IsRepG0*4 + ebx*4] + call .RangeDecoderBitDecode + jc .111 + mov eax, ebx + shl eax, .kNumPosBitsMax + add eax, edx + lea eax, [ebp + .p + .IsRep0Long*4 + eax*4] + call .RangeDecoderBitDecode + jc .1101 + cmp bl, 7 + setae bl + lea ebx, [9 + ebx + ebx] + xor edx, edx + sub edx, [ebp+.rep0] + mov al, [edi + edx] + stosb + mov [ebp+.previousByte], al + jmp .main_loop +.111: + lea eax, [ebp + .p + .IsRepG1*4 + ebx*4] + call .RangeDecoderBitDecode + mov eax, [ebp+.rep1] + jnc .l3 +.l1: + lea eax, [ebp + .p + .IsRepG2*4 + ebx*4] + call .RangeDecoderBitDecode + mov eax, [ebp+.rep2] + jnc .l2 + xchg [ebp+.rep3], eax +.l2: + push [ebp+.rep1] + pop [ebp+.rep2] +.l3: + xchg eax, [ebp+.rep0] + mov [ebp+.rep1], eax +.1101: + lea eax, [ebp + .p + .RepLencoder*4] + call .LzmaLenDecode + cmp bl, 7 + setc bl + adc bl, bl + xor bl, 3 + add bl, 8 + jmp .repmovsb +.10: + mov eax, [ebp+.rep0] + xchg eax, [ebp+.rep1] + xchg eax, [ebp+.rep2] + xchg eax, [ebp+.rep3] + cmp bl, 7 + setc bl + adc bl, bl + xor bl, 3 + add bl, 7 + lea eax, [ebp + .p + .Lencoder*4] + call .LzmaLenDecode + mov eax, .kNumLenToPosStates-1 + cmp eax, ecx + jb @f + mov eax, ecx +@@: + push ecx + mov ecx, .kNumPosSlotBits + shl eax, cl + lea eax, [ebp + .p+.PosSlot*4 + eax*4] + call .RangeDecoderBitTreeDecode + mov [ebp+.rep0], ecx + cmp ecx, .kStartPosModelIndex + jb .l6 + push ecx + mov eax, ecx + and eax, 1 + shr ecx, 1 + or eax, 2 + dec ecx + shl eax, cl + mov [ebp+.rep0], eax + pop edx + cmp edx, .kEndPosModelIndex + jae .l5 + sub eax, edx + lea eax, [ebp + .p + (.SpecPos - 1)*4 + eax*4] + call .RangeDecoderReverseBitTreeDecode + add [ebp+.rep0], ecx + jmp .l6 +.l5: + sub ecx, .kNumAlignBits + call .RangeDecoderDecodeDirectBits + mov ecx, .kNumAlignBits + shl eax, cl + add [ebp+.rep0], eax + lea eax, [ebp+.p+.Align_*4] + call .RangeDecoderReverseBitTreeDecode + add [ebp+.rep0], ecx +.l6: + pop ecx + inc [ebp+.rep0] + jz .main_loop_done +.repmovsb: + add ecx, .kMatchMinLen +.repmovsbz: + push esi +.repmovsbr: + mov eax, [ebp+.rep0] + cmp eax, [ebp+.dictSize] + jae return.err + mov esi, edi + sub esi, eax + mov eax, [ebp+streamInfo.bufPtr] + sub eax, esi + ja .repmovsb0 + mov eax, [ebp+.outEnd] + sub eax, edi + push ecx + cmp ecx, eax + jb @f + mov ecx, eax +@@: + sub [esp], ecx + rep movsb + pop ecx + jz .repmovsb1 + pop [ebp+.inPtr] + mov [ebp+.state], ebx + mov [ebp+.ecx], ecx + mov [ebp+.continue], .restart_repmovsb + popad + ret +.repmovsb0: + mov edx, [ebp+.dictSize] + cmp edx, [ebp+streamInfo.bufSize] + jnz return.err + add esi, edx + push ecx + cmp ecx, eax + jb @f + mov ecx, eax +@@: + mov eax, [ebp+.outEnd] + sub eax, edi + cmp ecx, eax + jb @f + mov ecx, eax +@@: + sub [esp], ecx + rep movsb + pop ecx + jnz .repmovsbr +.repmovsb1: + pop esi + mov al, [edi-1] + mov [ebp+.previousByte], al + jmp .main_loop +.main_loop_done: + mov [ebp+.state], ebx + mov [ebp+.continue], .main_loop + mov [ebp+.inPtr], esi + popad + ret +.restart_repmovsb: + mov ecx, [ebp+.ecx] + jmp .repmovsbz + +.RangeDecoderBitDecode: +; in: eax->prob +; out: CF=bit; destroys eax + push edx + mov edx, [ebp+.range] + shr edx, .kNumBitModelTotalBits + imul edx, [eax] + cmp [ebp+.code], edx + jae .ae + mov [ebp+.range], edx + mov edx, .kBitModelTotal + sub edx, [eax] + shr edx, .kNumMoveBits + add [eax], edx + clc +.n: + lahf + cmp [ebp+.range], .kTopValue + jae @f + shl [ebp+.range], 8 + shl [ebp+.code], 8 + sub [ebp+.inLen], 1 + js .refill1 +.refilled1: + lodsb + mov byte [ebp+.code], al +@@: + sahf + pop edx + ret +.ae: + sub [ebp+.range], edx + sub [ebp+.code], edx + mov edx, [eax] + shr edx, .kNumMoveBits + sub [eax], edx + stc + jmp .n + +.refill1: + push eax + call .refill + pop eax + jmp .refilled1 + +.refill: + mov eax, [ebp+.inStream] + cmp dword [eax+streamInfo.fullSize+4], 0 + jnz @f + cmp dword [eax+streamInfo.fullSize], 0 + jz return.err +@@: + call fillBuf + mov esi, [eax+streamInfo.bufPtr] + mov eax, [eax+streamInfo.bufDataLen] + dec eax + js return.err + mov [ebp+.inLen], eax + ret + +.refill2: + call .refill + jmp .refilled2 + +.RangeDecoderDecodeDirectBits: +; in: ecx=numTotalBits +; out: eax=result; destroys edx + xor eax, eax +.l: + shr [ebp+.range], 1 + shl eax, 1 + mov edx, [ebp+.code] + sub edx, [ebp+.range] + jb @f + mov [ebp+.code], edx + or eax, 1 +@@: + cmp [ebp+.range], .kTopValue + jae @f + shl [ebp+.range], 8 + shl [ebp+.code], 8 + push eax + dec [ebp+.inLen] + js .refill2 +.refilled2: + lodsb + mov byte [ebp+.code], al + pop eax +@@: + loop .l + ret + +.LzmaLiteralDecode: +; in: eax->probs +; out: al=byte; destroys edx + push ecx + mov ecx, 1 +@@: + push eax + lea eax, [eax+ecx*4] + call .RangeDecoderBitDecode + pop eax + adc cl, cl + jnc @b +.LzmaLiteralDecode.ret: + mov al, cl + pop ecx + ret +.LzmaLiteralDecodeMatch: +; in: eax->probs, dl=matchByte +; out: al=byte; destroys edx + push ecx + mov ecx, 1 +.LzmaLiteralDecodeMatch.1: + add dl, dl + setc ch + push eax + lea eax, [eax+ecx*4+0x100*4] + call .RangeDecoderBitDecode + pop eax + adc cl, cl + jc .LzmaLiteralDecode.ret + xor ch, cl + test ch, 1 + mov ch, 0 + jnz @b + jmp .LzmaLiteralDecodeMatch.1 + +.LzmaLenDecode: +; in: eax->prob, edx=posState +; out: ecx=len + push eax + add eax, .LenChoice*4 + call .RangeDecoderBitDecode + pop eax + jnc .0 + push eax + add eax, .LenChoice2*4 + call .RangeDecoderBitDecode + pop eax + jc @f + mov ecx, .kLenNumMidBits + shl edx, cl + lea eax, [eax + .LenMid*4 + edx*4] + call .RangeDecoderBitTreeDecode + add ecx, .kLenNumLowSymbols + ret +@@: + add eax, .LenHigh*4 + mov ecx, .kLenNumHighBits + call .RangeDecoderBitTreeDecode + add ecx, .kLenNumLowSymbols + .kLenNumMidSymbols + ret +.0: + mov ecx, .kLenNumLowBits + shl edx, cl + lea eax, [eax + .LenLow*4 + edx*4] +.RangeDecoderBitTreeDecode: +; in: eax->probs,ecx=numLevels +; out: ecx=length; destroys edx + push ebx + mov edx, 1 + mov ebx, edx +@@: + push eax + lea eax, [eax+edx*4] + call .RangeDecoderBitDecode + pop eax + adc dl, dl + add bl, bl + loop @b + sub dl, bl + pop ebx + mov ecx, edx + ret +.RangeDecoderReverseBitTreeDecode: +; in: eax->probs,ecx=numLevels +; out: ecx=length; destroys edx + push ebx ecx + mov edx, 1 + xor ebx, ebx +@@: + push eax + lea eax, [eax+edx*4] + call .RangeDecoderBitDecode + lahf + adc edx, edx + sahf + rcr ebx, 1 + pop eax + loop @b + pop ecx + rol ebx, cl + mov ecx, ebx + pop ebx + ret + +; LZMA parameters: +; db lc + 9 * (lp + 5 * pb) +; dd dictionarySize + +lzma_get_buf_size: + cmp dword [esi-4], 5 + jb return.err + push ecx + lodsb + aam 9 + mov cl, al + mov al, ah + aam 5 + add cl, al + mov eax, LZMA_LIT_SIZE + shl eax, cl + lea eax, [lzma_decoder.basesize+eax*4] + pop ecx + mov edx, [esi] + ret + +lzma_init_decoder: + lodsb + aam 9 + mov [ebp+lzma_decoder.lc], al + mov al, ah + aam 5 + mov [ebp+lzma_decoder.lp], al + mov [ebp+lzma_decoder.pb], ah + cmp ah, lzma_decoder.kNumPosBitsMax + ja return.err + mov cl, ah + lodsd + mov [ebp+lzma_decoder.dictSize], eax + push 1 + pop eax + shl eax, cl + dec eax + mov [ebp+lzma_decoder.posStateMask], eax + mov cl, [ebp+lzma_decoder.lp] + push 1 + pop eax + shl eax, cl + dec eax + mov [ebp+lzma_decoder.literalPosMask], eax + mov [ebp+streamInfo.fillBuf], lzma_decoder.fillBuf + mov [ebp+lzma_decoder.continue], lzma_decoder.start + xor eax, eax + mov [ebp+lzma_decoder.previousByte], al + mov [ebp+lzma_decoder.state], eax + inc eax + lea edi, [ebp+lzma_decoder.rep0] + stosd + stosd + stosd + mov eax, LZMA_LIT_SIZE + mov cl, [ebp+lzma_decoder.lc] + add cl, [ebp+lzma_decoder.lp] + shl eax, cl + lea ecx, [eax+lzma_decoder.Literal] + mov eax, lzma_decoder.kBitModelTotal/2 + lea edi, [ebp+lzma_decoder.p] + rep stosd + ret diff --git a/programs/fs/kfar/trunk/kfar_arc/ppmd.inc b/programs/fs/kfar/trunk/kfar_arc/ppmd.inc new file mode 100644 index 0000000000..3704e40fc1 --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/ppmd.inc @@ -0,0 +1,1485 @@ +; PPMD decoder, ported from C++ sources of 7-Zip (c) Igor Pavlov +; C++ code is based on Dmitry Shkarin's PPMdH code +uglobal +ppmd_decoder.NS2Indx rb 256 +ppmd_decoder.NS2BSIndx rb 256 +ppmd_decoder.HB2Flag rb 256 +ppmd_decoder.Indx2Units rb ppmd_decoder.N_INDEXES +ppmd_decoder.Units2Indx rb 128 +endg + +iglobal +label ppmd_decoder.InitBinEsc word + dw 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051 +ppmd_decoder.ExpEscape db 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 +endg + +init_ppmd: +; NS2Indx table + mov edi, ppmd_decoder.NS2Indx + xor eax, eax + stosb + inc eax + stosb + inc eax + stosb + mov edx, 3-256 +@@: + lea ecx, [eax-1] + inc eax + add edx, ecx + jc @f + rep stosb + jmp @b +@@: + sub ecx, edx + rep stosb +; NS2BSIndx table + xor eax, eax + stosb + add al, 2 + stosb + add al, 2 + mov cl, 9 + rep stosb + add al, 2 + mov cl, 256-11 + rep stosb +; HB2Flag table + mov cl, 0x40/4 + xor eax, eax + rep stosd + mov al, 8 + mov cl, 0x100-0x40 + rep stosb +; Indx2Units table + mov eax, 0x04030201 + stosd + mov eax, 0x0C0A0806 + stosd + mov eax, 0x1815120F + stosd + mov al, 0x1C +@@: + stosb + add al, 4 + cmp al, 0x80 + jbe @b +; Units2Indx table + xor eax, eax + xor edx, edx + inc edx + xor ecx, ecx +@@: + cmp [ppmd_decoder.Indx2Units+eax], dl + adc al, 0 + stosb + inc edx + cmp dl, 0x80 + jbe @b + ret + +ppmd_decoder: +virtual at 0 +; base is standard structure +.outStream rb streamInfo.size +.inStream dd ? + +; RangeDecoder data +.inLen dd ? +.inPtr dd ? +.code dd ? +.range dd ? + +.outSize dd ? ; number of bytes rest for output + +; PPMD data +.order db ? +.GlueCount db ? +.bInited db ? + rb 1 +.usedMemorySize dd ? + +; CSubAllocator constants +.N1 = 4 +.N2 = 4 +.N3 = 4 +.N4 = (128+3-1*.N1-2*.N2-3*.N3)/4 +.UNIT_SIZE = 12 +.N_INDEXES = .N1+.N2+.N3+.N4 +.kExtraSize = .UNIT_SIZE*3 +.kMaxMemBlockSize = 0xFFFFFFFF - .kExtraSize + +; CSubAllocator data +.HeapStart dd ? +.LoUnit dd ? +.HiUnit dd ? +.pText dd ? +.UnitsStart dd ? +.FreeList rd .N_INDEXES + +; Context constants +.INT_BITS = 7 +.PERIOD_BITS = 7 +.TOT_BITS = .INT_BITS + .PERIOD_BITS +.INTERVAL = 1 shl .INT_BITS +.BIN_SCALE = 1 shl .TOT_BITS +.MAX_FREQ = 124 + +.kMaxOrderCompress = 32 +.MAX_O = 255 + +; CDecodeInfo (inherits from CInfo) data +; SEE2_CONTEXT is 4 bytes long +.SEE2Cont rd 25*16 +.DummySEE2Cont dd ? +.MinContext dd ? +.MaxContext dd ? +.FoundState dd ? ; found next state transition +.NumMasked dd ? +.InitEsc dd ? +.OrderFall dd ? +.RunLength dd ? +.InitRL dd ? +.CharMask rb 256 +.EscCount db ? +.PrintCount db ? +.PrevSuccess db ? +.HiBitsFlag db ? +.BinSumm rw 128*64 + +.basesize = $ +.Base: +; rb .kExtraSize + [.usedMemorySize] +end virtual + +.init: + mov eax, [eax+.inStream] + call fillBuf + mov esi, [eax+streamInfo.bufPtr] + mov eax, [eax+streamInfo.bufDataLen] + sub eax, 5 + jb return.err + mov [ebp+.inLen], eax + inc esi + lodsd + mov [ebp+.inPtr], esi + bswap eax + mov [ebp+.code], eax + or [ebp+.range], -1 + mov [ebp+.bInited], 1 + call .StartModelRare + mov eax, ebp + jmp .mainloop + +.fillBuf: + mov ebp, eax + mov [eax+.outSize], ecx + cmp [eax+.bInited], 0 + jz .init +.mainloop: + sub [ebp+.outSize], 1 + js .mainloopdone +; cmp edi, 0xde070+0x18 +; jnz @f +; int3 +;@@: + call .DecodeSymbol + jmp .mainloop +.mainloopdone: + popad + ret + +.GetBinSumm: +; CInfo::GetBinSumm(ebx=rs, ecx=numStates) + movzx eax, [ebp+.PrevSuccess] + movzx edx, [.NS2BSIndx+ecx-1] + add eax, edx + mov edx, [ebp+.FoundState] + movzx edx, byte [edx] + movzx edx, [.HB2Flag+edx] + mov [ebp+.HiBitsFlag], dl + add eax, edx + movzx edx, byte [ebx] + movzx edx, [.HB2Flag+edx] + lea eax, [eax+edx*2] + mov edx, [ebp+.RunLength] + shr edx, 26 + and edx, 0x20 + add eax, edx + movzx edx, byte [ebx+1] + shl edx, 6 + add eax, edx + lea ecx, [ebp+.BinSumm+eax*2-2*64] + ret + +.StartModelRare: +; CInfo::StartModelRare(.order) + mov [ebp+.EscCount], 1 + mov [ebp+.PrintCount], 1 +; N.B. +; 1. Original code has some handling of [.order]<2, but this handling is incorrect +; and causes exception (access violation). +; 2. 7-Zip never generates archives with [.order]<2 due to input preprocessing +; (for PPMd method in switch -mo= archiver checks that 2 <= n <= 32). +; 3. If manually created archive says [.order]<2, the exception will be generated +; in StartModelRare, but it will be handled in Code() resulting in "data error". + cmp [ebp+.order], 2 + jb return.err + mov byte [ebp+.DummySEE2Cont+2], .PERIOD_BITS + +.RestartModelRare: +; CInfo::RestartModelRare(void) + push edi + lea edi, [ebp+.CharMask] + xor eax, eax + push 0x40 + pop ecx + rep stosd +; CSubAllocator::InitSubAllocator start + mov [ebp+.GlueCount], al + lea edi, [ebp+.FreeList] + mov cl, .N_INDEXES + rep stosd + mov ebx, [ebp+.HeapStart] + mov [ebp+.pText], ebx + add ebx, [ebp+.usedMemorySize] + mov [ebp+.HiUnit], ebx + mov eax, [ebp+.usedMemorySize] + xor edx, edx + mov cl, 8*.UNIT_SIZE + div ecx + imul eax, 7*.UNIT_SIZE + sub ebx, eax + mov [ebp+.LoUnit], ebx + mov [ebp+.UnitsStart], ebx +; CSubAllocator::InitSubAllocator end + pop edi + movzx eax, [ebp+.order] + cmp al, 12 + jb @f + mov al, 12 +@@: + neg eax + dec eax + mov [ebp+.InitRL], eax + mov [ebp+.RunLength], eax + call .AllocContext + mov [ebp+.MinContext], eax + mov [ebp+.MaxContext], eax + and dword [eax+8], 0 + mov esi, eax + movzx edx, [ebp+.order] + mov [ebp+.OrderFall], edx + mov dword [eax], 257*10000h+256 + mov ecx, 256/2 + call .AllocUnits + mov [ebp+.FoundState], eax + mov [esi+4], eax + push edi + mov edi, eax + xor eax, eax + mov [ebp+.PrevSuccess], al +@@: + stosb + mov byte [edi], 1 + and dword [edi+1], 0 + add edi, 5 + inc al + jnz @b + lea edi, [ebp+.BinSumm] + push 2 + pop ecx +.rmr1: + mov esi, .InitBinEsc +@@: + lodsw + xor edx, edx + div ecx + sub eax, .BIN_SCALE + neg eax + mov [edi+2*8], ax + mov [edi+2*16], ax + mov [edi+2*24], ax + mov [edi+2*32], ax + mov [edi+2*40], ax + mov [edi+2*48], ax + mov [edi+2*56], ax + stosw + cmp esi, .InitBinEsc+2*8 + jb @b + add edi, 128-16 + inc ecx + cmp ecx, 128+2 + jb .rmr1 + lea edi, [ebp+.SEE2Cont] + mov eax, (10 shl (.PERIOD_BITS-4)) + ((.PERIOD_BITS-4) shl 16) + (4 shl 24) + push 25 + pop edx +@@: + push 16 + pop ecx + rep stosd + add ax, 5 shl (.PERIOD_BITS-4) + dec edx + jnz @b + pop edi + ret + +.CreateSuccessors: +; CInfo::CreateSuccessors(bool al=skip,STATE* esi=p1) + push ebx edi + mov ebx, [ebp+.MinContext] ; ebx=pc + mov ecx, [ebp+.FoundState] + mov ecx, [ecx+2] ; ecx=UpBranch + sub esp, .MAX_O*4 ; esp=ps + mov edi, esp ; edi=pps + test al, al + jnz @f + mov eax, [ebp+.FoundState] + stosd + cmp dword [ebx+8], 0 + jz .csnoloop +@@: + test esi, esi + jz .csloopstart + mov edx, esi ; edx=p + mov ebx, [ebx+8] + jmp .csloopentry +.csloopstart: + mov ebx, [ebx+8] + lea edx, [ebx+2] + cmp word [ebx], 1 + jz .csloopentry + mov edx, [ebx+4] + mov eax, [ebp+.FoundState] + sub edx, 6 + mov al, [eax] +@@: + add edx, 6 + cmp al, [edx] + jnz @b +.csloopentry: + cmp ecx, [edx+2] + jz @f + mov ebx, [edx+2] + jmp .csnoloop +@@: + mov [edi], edx + add edi, 4 + cmp dword [ebx+8], 0 + jnz .csloopstart +.csnoloop: + cmp edi, esp + jz .csr + push eax + push eax + mov al, [ecx] + mov [esp], al + add ecx, 1 + mov [esp+2], ecx + mov ah, [ebx+3] + cmp word [ebx], 1 + jz .cs2 + mov edx, [ebx+4] + sub edx, 6 +@@: + add edx, 6 + cmp [edx], al + jnz @b + movzx edx, byte [edx+1] + sub edx, 1 ; edx=cf + movzx ecx, word [ebx+2] + movzx eax, word [ebx] + sub ecx, eax + sub ecx, edx ; ecx=s0 + lea eax, [edx+edx] + cmp eax, ecx + ja .cs0 + lea eax, [edx*5] + cmp eax, ecx + seta ah + jmp .cs1 +.cs0: + lea eax, [eax+ecx*2] + lea eax, [eax+ecx-1] + add ecx, ecx + xor edx, edx + div ecx + mov ah, al +.cs1: + add ah, 1 +.cs2: + mov [esp+1], ah + sub edi, 8 +.cs3: +; PPM_CONTEXT::createChild(this=ebx,pStats=[edi+4],FirstState=esp) begin + call .AllocContext + test eax, eax + jz .csr0 + mov word [eax], 1 + mov dx, [esp] + mov [eax+2], dx + mov edx, [esp+2] + mov [eax+4], edx + mov [eax+8], ebx + mov edx, [edi+4] + mov [edx+2], eax +; PPM_CONTEXT::createChild end + mov ebx, eax + sub edi, 4 + cmp edi, esp + jnz .cs3 + pop eax eax +.csr: + mov eax, ebx +@@: + add esp, .MAX_O*4 + pop edi ebx + ret +.csr0: + pop eax eax + xor eax, eax + jmp @b + +; CInfo::UpdateModel(void) +.UpdateModel: + mov ebx, [ebp+.FoundState] + xor esi, esi ; esi=p + movzx eax, word [ebx] + mov ebx, [ebx+2] ; ebx=fs.Successor + push eax + cmp ah, .MAX_FREQ/4 + jae .um2 + mov eax, [ebp+.MinContext] + mov eax, [eax+8] + test eax, eax + jz .um2 + cmp word [eax], 1 + jz .um1 + push eax + mov esi, [eax+4] + mov al, [esp+4] + cmp al, [esi] + jz .um0 +@@: + add esi, 6 + cmp al, [esi] + jnz @b + mov al, [esi+1] + cmp al, [esi-6+1] + jb @f + mov eax, [esi] + xchg [esi-6], eax + mov [esi], eax + mov ax, [esi+4] + xchg [esi-6+4], ax + mov [esi+4], ax + sub esi, 6 +@@: +.um0: + pop eax + cmp byte [esi+1], .MAX_FREQ-9 + jae @f + add byte [esi+1], 2 + add word [eax+2], 2 +@@: + jmp .um2 +.um1: + lea esi, [eax+2] + cmp byte [esi+1], 32 + adc byte [esi+1], 0 +.um2: + cmp [ebp+.OrderFall], 0 + jnz .um3 + pop eax + mov al, 1 + call .CreateSuccessors + mov [ebp+.MinContext], eax + mov [ebp+.MaxContext], eax + mov edx, [ebp+.FoundState] + mov [edx+2], eax + test eax, eax + jz .RestartModel + ret +.um3: + mov edx, [ebp+.pText] + mov al, [esp] + mov [edx], al + add edx, 1 ; edx=Successor + mov [ebp+.pText], edx + cmp edx, [ebp+.UnitsStart] + jae .RestartModelPop + test ebx, ebx + jz .um4 + cmp ebx, [ebp+.pText] + ja @f + push edx + xor eax, eax + call .CreateSuccessors + pop edx + mov ebx, eax + test eax, eax + jz .RestartModelPop +@@: + sub [ebp+.OrderFall], 1 + jnz @f + mov edx, ebx + xor ecx, ecx + mov eax, [ebp+.MinContext] + cmp eax, [ebp+.MaxContext] + setnz cl + sub [ebp+.pText], ecx +@@: + jmp .um5 +.um4: + mov eax, [ebp+.FoundState] + mov [eax+2], edx + mov ebx, [ebp+.MinContext] +.um5: + mov eax, [ebp+.MinContext] + movzx ecx, word [eax] ; ecx=ns + movzx eax, word [eax+2] + sub eax, ecx + push eax + movzx eax, byte [esp+5] + sub eax, 1 + sub [esp], eax ; [esp]=s0 + mov esi, [ebp+.MaxContext] ; ebx=pc + cmp esi, [ebp+.MinContext] + jz .um12 +.um6: + movzx eax, word [esi] + cmp eax, 1 + jz .um8 + push eax + shr eax, 1 + jc .um7 + push esi + mov esi, [esi+4] + call .ExpandUnits + pop esi + mov [esi+4], eax + test eax, eax + jz .RestartModelPop3 +.um7: + pop eax + add eax, eax + cmp eax, ecx + adc word [esi+2], 0 + add eax, eax + cmp eax, ecx + ja @f + lea eax, [eax+eax+1] + cmp word [esi+2], ax + ja @f + add word [esi+2], 2 +@@: + push edx + jmp .um9 +.um8: + push edx ecx + mov ecx, 1 + call .AllocUnits + pop ecx + test eax, eax + jz .RestartModelPop3 + mov dx, [esi+2] + mov [eax], dx + mov edx, [esi+4] + mov [eax+2], edx + mov [esi+4], eax + movzx edx, byte [eax+1] + add edx, edx + cmp edx, (.MAX_FREQ/4-1)*2 + jb @f + mov edx, .MAX_FREQ-4 +@@: + mov [eax+1], dl + add edx, [ebp+.InitEsc] + cmp ecx, 4 + sbb edx, -1 + mov [esi+2], dx +.um9: + movzx edx, word [esi+2] + mov eax, [esp+4] + push ecx + lea ecx, [eax+edx] ; ecx=sf + add edx, 6 + movzx eax, byte [esp+13] + add eax, eax + imul eax, edx ; eax=cf + lea edx, [ecx*3] + add edx, edx + cmp eax, edx + jae .um10 + mov edx, 1 + cmp ecx, eax + adc edx, 0 + shl ecx, 2 + add eax, 1 + cmp ecx, eax + adc edx, 0 + add word [esi+2], 3 + jmp .um11 +.um10: + lea ecx, [ecx*3] + lea edx, [ecx*3] + add eax, 1 + push 4 + cmp edx, eax + adc dword [esp], 0 + add edx, ecx + cmp edx, eax + adc dword [esp], 0 + add edx, ecx + cmp edx, eax + adc dword [esp], 0 + pop edx + add [esi+2], dx +.um11: + movzx eax, word [esi] + lea eax, [eax*3] + add eax, eax + add eax, [esi+4] + mov ecx, [esp+4] + mov [eax+2], ecx + mov cl, [esp+12] + mov [eax], cl + mov [eax+1], dl + add word [esi], 1 + pop ecx edx + mov esi, [esi+8] + cmp esi, [ebp+.MinContext] + jnz .um6 +.um12: + pop eax + pop eax + mov [ebp+.MinContext], ebx + mov [ebp+.MaxContext], ebx + ret +.RestartModelPop3: + pop eax + pop eax +.RestartModelPop: + pop eax +.RestartModel: + call .RestartModelRare + mov [ebp+.EscCount], 0 + mov [ebp+.PrintCount], 0xFF + ret + +.rescale: + mov esi, [ebp+.MinContext] + movzx ecx, word [esi] + push ecx ; [esp]=OldNS + sub ecx, 1 + mov ebx, [ebp+.FoundState] + cmp ebx, [esi+4] + jz .r1 +.r0: + mov ax, [ebx] + xchg [ebx-6], ax + mov [ebx], ax + mov eax, [ebx+2] + xchg [ebx-6+2], eax + mov [ebx+2], eax + sub ebx, 6 + cmp ebx, [esi+4] + jnz .r0 +.r1: + add byte [ebx+1], 4 + add word [esi+2], 4 + movzx eax, byte [ebx+1] + movzx edx, word [esi+2] + sub edx, eax ; edx=EscFreq + cmp [ebp+.OrderFall], 1 + sbb eax, -1 + shr eax, 1 + mov [ebx+1], al + mov [esi+2], ax +.r2: + add ebx, 6 + movzx eax, byte [ebx+1] + sub edx, eax + cmp [ebp+.OrderFall], 1 + sbb eax, -1 + shr eax, 1 + mov [ebx+1], al + add [esi+2], ax + cmp al, [ebx-6+1] + jbe .r3 + push ecx + push ebx + push dword [ebx] + push word [ebx+4] +@@: + mov ecx, [ebx-6] + mov [ebx], ecx + mov cx, [ebx-6+4] + mov [ebx+4], cx + sub ebx, 6 + cmp ebx, [esi+4] + jz @f + cmp al, [ebx-6+1] + ja @b +@@: + pop word [ebx+4] + pop dword [ebx] + pop ebx + pop ecx +.r3: + sub ecx, 1 + jnz .r2 + cmp byte [ebx+1], 0 + jnz .r4 +@@: + add ecx, 1 + sub ebx, 6 + cmp byte [ebx+1], 0 + jz @b + add edx, ecx + sub word [esi], cx + cmp word [esi], 1 + jnz .r4 + pop ebx + mov eax, [esi+4] + movzx ecx, word [eax+4] + push ecx + push dword [eax] + movzx eax, byte [eax+1] +@@: + add eax, 1 + shr eax, 1 + shr edx, 1 + cmp edx, 1 + ja @b + mov [esp+1], al + add ebx, 1 + shr ebx, 1 + mov eax, [esi+4] + call .FreeUnits + lea ebx, [esi+2] + mov [ebp+.FoundState], ebx + pop dword [ebx] + pop eax + mov [ebx+4], ax + ret +.r4: + add edx, 1 + shr edx, 1 + add [esi+2], dx + pop ebx + add ebx, 1 + shr ebx, 1 + movzx ecx, word [esi] + add ecx, 1 + shr ecx, 1 + cmp ebx, ecx + jz @f + mov eax, [esi+4] + call .ShrinkUnits + mov [esi+4], eax +@@: + mov eax, [esi+4] + mov [ebp+.FoundState], eax + ret + +.DecodeSymbol: +; CDecodeInfo::DecodeSymbol + mov esi, [ebp+.MinContext] + cmp word [esi], 1 + jz .binsymbol +; CDecodeInfo::DecodeSymbol1 start + mov ebx, [esi+4] ; state + movzx ecx, word [esi+2] + mov eax, [ebp+.range] + xor edx, edx + div ecx + mov [ebp+.range], eax + mov ecx, eax + mov eax, [ebp+.code] + xor edx, edx + div ecx + movzx edx, byte [ebx+1] + cmp eax, edx + jae .ds0 + push edx + add edx, edx + cmp dx, [esi+2] + pop edx + seta [ebp+.PrevSuccess] + movzx eax, [ebp+.PrevSuccess] + add [ebp+.RunLength], eax + xor eax, eax + call .RangeDecoder.Decode + mov [ebp+.FoundState], ebx + add edx, 4 + mov [ebx+1], dl + add word [esi+2], 4 + cmp edx, .MAX_FREQ + jbe @f + call .rescale +@@: + jmp .dscmn +.ds0: + mov [ebp+.PrevSuccess], 0 + movzx ecx, word [esi] + sub ecx, 1 + push eax +.ds1: + add ebx, 6 + movzx eax, byte [ebx+1] + add edx, eax + cmp edx, [esp] + ja .ds2 + sub ecx, 1 + jnz .ds1 + pop eax + mov eax, [ebp+.FoundState] + movzx eax, byte [eax] + mov al, [.HB2Flag+eax] + mov [ebp+.HiBitsFlag], al + mov eax, edx + movzx edx, word [esi+2] + sub edx, eax + call .RangeDecoder.Decode + mov al, [ebp+.EscCount] + movzx edx, byte [ebx] + mov [ebp+.CharMask+edx], al + movzx ecx, word [esi] + mov [ebp+.NumMasked], ecx + sub ecx, 1 +@@: + sub ebx, 6 + movzx edx, byte [ebx] + mov [ebp+.CharMask+edx], al + sub ecx, 1 + jnz @b + mov [ebp+.FoundState], ecx + jmp .dscmn +.ds2: + pop eax + mov eax, edx + movzx edx, byte [ebx+1] + sub eax, edx + call .RangeDecoder.Decode +.update1: + mov [ebp+.FoundState], ebx + add byte [ebx+1], 4 + add word [esi+2], 4 + mov al, [ebx+1] + cmp al, [ebx-6+1] + jbe @f + mov eax, [ebx] + xchg eax, [ebx-6] + mov [ebx], eax + mov ax, [ebx+4] + xchg ax, [ebx-6+4] + mov [ebx+4], ax + sub ebx, 6 + mov [ebp+.FoundState], ebx + cmp byte [ebx+1], .MAX_FREQ + jbe @f + call .rescale +@@: + jmp .dscmn +; CDecodeInfo::DecodeSymbol1 end +.binsymbol: +; CDecodeInfo::DecodeBinSymbol start + lea ebx, [esi+2] + mov ecx, [esi+8] + movzx ecx, word [ecx] + call .GetBinSumm + movzx eax, word [ecx] + call .RangeDecoder.DecodeBit + jc .ds3 + mov [ebp+.FoundState], ebx + cmp byte [ebx+1], 128 + adc byte [ebx+1], 0 + movzx eax, word [ecx] + add eax, 1 shl (.PERIOD_BITS-2) + shr eax, .PERIOD_BITS + sub eax, .INTERVAL + sub [ecx], ax + mov [ebp+.PrevSuccess], 1 + add [ebp+.RunLength], 1 + jmp .dscmn +.ds3: + movzx eax, word [ecx] + add eax, 1 shl (.PERIOD_BITS-2) + shr eax, .PERIOD_BITS + sub [ecx], ax + movzx eax, word [ecx] + shr eax, 10 + movzx eax, [.ExpEscape+eax] + mov [ebp+.InitEsc], eax + mov [ebp+.NumMasked], 1 + mov al, [ebp+.EscCount] + movzx edx, byte [ebx] + mov [ebp+.CharMask+edx], al + mov [ebp+.PrevSuccess], 0 + and [ebp+.FoundState], 0 +; CDecodeInfo::DecodeBinSymbol end +.dscmn: + cmp [ebp+.FoundState], 0 + jnz .dsfnd +.ds4: + add [ebp+.OrderFall], 1 + mov eax, [ebp+.MinContext] + mov eax, [eax+8] + test eax, eax + jz return.err ; no end-of-stream mark + mov [ebp+.MinContext], eax + movzx ecx, word [eax] + sub ecx, [ebp+.NumMasked] + jz .ds4 +; CDecodeInfo::DecodeSymbol2 start + call .makeEscFreq2 + push eax + mov ebx, [esi+4] + sub ebx, 6 + sub esp, 256*4 + mov esi, esp + xor eax, eax + push eax +@@: + add ebx, 6 + mov al, [ebx] + mov al, [ebp+.CharMask+eax] + cmp al, [ebp+.EscCount] + jz @b + mov al, [ebx+1] + add [esp], eax + mov [esi], ebx + add esi, 4 + sub ecx, 1 + jnz @b + add edx, [esp] + mov ecx, edx + mov eax, [ebp+.range] + xor edx, edx + div ecx + mov [ebp+.range], eax + mov eax, [ebp+.code] + xor edx, edx + div [ebp+.range] + cmp eax, [esp] + jae .ds5 + pop ecx + mov esi, esp + xor ecx, ecx +@@: + mov ebx, [esi] + add esi, 4 + movzx edx, byte [ebx+1] + add ecx, edx + cmp eax, ecx + jae @b + mov eax, ecx + movzx edx, byte [ebx+1] + sub eax, edx + call .RangeDecoder.Decode + add esp, 256*4 + pop eax + mov cl, [eax+2] + cmp cl, .PERIOD_BITS + jae @f + sub byte [eax+3], 1 + jnz @f + shl word [eax], 1 + mov dl, 3 + shl dl, cl + mov [eax+3], dl + add byte [eax+2], 1 +@@: +.update2: + mov [ebp+.FoundState], ebx + add byte [ebx+1], 4 + mov esi, [ebp+.MinContext] + add word [esi+2], 4 + cmp byte [ebx+1], .MAX_FREQ + jbe @f + call .rescale +@@: + add [ebp+.EscCount], 1 + mov eax, [ebp+.InitRL] + mov [ebp+.RunLength], eax + jmp .dsfnd +.ds5: + pop eax + mov edx, ecx + sub edx, eax + call .RangeDecoder.Decode + mov eax, [ebp+.MinContext] + movzx eax, word [eax] + mov ebx, eax + sub ebx, [ebp+.NumMasked] + mov [ebp+.NumMasked], eax + mov esi, esp + mov al, [ebp+.EscCount] +@@: + mov edx, [esi] + add esi, 4 + movzx edx, byte [edx] + mov [ebp+.CharMask+edx], al + sub ebx, 1 + jnz @b + add esp, 256*4 + pop eax + add word [eax], cx +; CDecodeInfo::DecodeSymbol2 end + cmp [ebp+.FoundState], 0 + jz .ds4 +.dsfnd: + mov eax, [ebp+.FoundState] + mov al, [eax] + stosb + +.NextContext: +; CInfo::NextContext(void) + mov ebx, [ebp+.FoundState] + mov ebx, [ebx+2] + cmp [ebp+.OrderFall], 0 + jnz .nc0 + cmp ebx, [ebp+.pText] + jbe .nc0 + mov [ebp+.MinContext], ebx + mov [ebp+.MaxContext], ebx + ret +.nc0: + call .UpdateModel + cmp [ebp+.EscCount], 0 + jz @f + ret +@@: + mov [ebp+.EscCount], 1 + push edi + lea edi, [ebp+.CharMask] + mov ecx, 256/4 + xor eax, eax + rep stosd + pop edi + ret + +.makeEscFreq2: +; CInfo::makeEscFreq2(ecx=Diff)->{eax->SEE2_CONTEXT,edx=scale} + mov esi, [ebp+.MinContext] + cmp word [esi], 256 + jz .mef0 + movzx edx, [.NS2Indx+ecx-1] + shl edx, 4 + mov eax, [esi+8] + movzx eax, word [eax] + sub ax, [esi] + cmp ecx, eax + adc edx, 0 + movzx eax, word [esi] + push edx + lea edx, [eax*9] + lea edx, [edx+eax*2] + movzx eax, word [esi+2] + cmp eax, edx + pop edx + setc al + movzx eax, al + lea edx, [edx+eax*2] + cmp ecx, [ebp+.NumMasked] + setc al + lea edx, [edx+eax*4] + add dl, [ebp+.HiBitsFlag] + lea eax, [ebp+edx*4+.SEE2Cont] + movzx edx, word [eax] + push ecx + mov cl, [eax+2] + shr edx, cl + sub [eax], dx + pop ecx + cmp edx, 1 + adc edx, 0 + ret +.mef0: + lea eax, [ebp+.DummySEE2Cont] + mov edx, 1 + ret + +.RangeDecoder.DecodeBit: +; CRangeDecoder::DecodeBit(eax=size0,numTotalBits=.TOT_BITS) + mov edx, [ebp+.range] + shr edx, .TOT_BITS + imul eax, edx + cmp [ebp+.code], eax + jae .rddb + mov [ebp+.range], eax + call .RangeDecoder.Normalize + clc + ret +.rddb: + sub [ebp+.code], eax + sub [ebp+.range], eax + call .RangeDecoder.Normalize + stc + ret + +.RangeDecoder.Decode: + imul eax, [ebp+.range] + sub [ebp+.code], eax + mov eax, [ebp+.range] + imul eax, edx + mov [ebp+.range], eax +.RangeDecoder.Normalize: + cmp byte [ebp+.range+3], 0 + jz @f + ret +@@: + sub [ebp+.inLen], 1 + js .refill +.filled: + shl [ebp+.range], 8 + shl [ebp+.code], 8 + mov eax, [ebp+.inPtr] + add [ebp+.inPtr], 1 + mov al, [eax] + mov byte [ebp+.code], al + jmp .RangeDecoder.Normalize +.refill: + mov eax, [ebp+.inStream] + call fillBuf + push [eax+streamInfo.bufPtr] + pop [ebp+.inPtr] + mov eax, [eax+streamInfo.bufDataLen] + sub eax, 1 + js return.err + mov [ebp+.inLen], eax + jmp .filled + +.GlueFreeBlocks: +; CSubAllocator::GlueFreeBlocks, called from AllocUnitsRare + push eax + mov [ebp+.GlueCount], 255 + mov edx, [ebp+.HeapStart] + add edx, [ebp+.usedMemorySize] + ; we need add extra MEM_BLK with Stamp=0 + and word [edx], 0 + add edx, .UNIT_SIZE + mov eax, [ebp+.LoUnit] + cmp eax, [ebp+.HiUnit] + jz @f + mov byte [eax], 0 +@@: + mov [edx+4], edx + mov [edx+8], edx + push ecx + xor ecx, ecx +.gfb1: + mov eax, [ebp+ecx*4+.FreeList] + test eax, eax + jz .gfb2 + push dword [eax] + pop dword [ebp+ecx*4+.FreeList] + mov [eax+8], edx + push edx + mov edx, [edx+4] + mov [eax+4], edx + mov [edx+8], eax + or word [eax], 0xFFFF + movzx edx, [.Indx2Units+ecx] + mov [eax+2], dx + pop edx + mov [edx+4], eax + jmp .gfb1 +.gfb2: + inc ecx + cmp ecx, .N_INDEXES + jb .gfb1 + mov ecx, edx +.gfb3: + mov ecx, [ecx+4] + cmp ecx, edx + jz .gfb5 +.gfb4: + movzx eax, word [ecx+2] + lea eax, [eax*3] + lea eax, [ecx+eax*4] + cmp word [eax], 0xFFFF + jnz .gfb3 + push eax + mov ax, [eax+2] + add ax, [ecx+2] + pop eax + jc .gfb3 + push edx + mov edx, [eax+4] + push dword [eax+8] + pop dword [edx+8] + mov edx, [eax+8] + push dword [eax+4] + pop dword [edx+4] + pop edx + mov ax, [eax+2] + add [ecx+2], ax + jmp .gfb4 +.gfb5: + mov ecx, [edx+4] + cmp ecx, edx + jz .gfb8 + mov eax, [ecx+4] + mov [eax+8], edx + mov [edx+4], eax + movzx eax, word [ecx+2] + push edx +.gfb6: + sub eax, 128 + jbe .gfb7 + mov edx, ecx + xchg edx, [ebp+.FreeList+(.N_INDEXES-1)*4] + mov [ecx], edx + add ecx, 128*.UNIT_SIZE + jmp .gfb6 +.gfb7: + add eax, 128 + movzx edx, [.Units2Indx+eax-1] + cmp [.Indx2Units+edx], al + jz @f + dec edx + push edx + movzx edx, [.Indx2Units+edx] + sub eax, edx + lea eax, [ebp+.FreeList+(eax-1)*4] + lea edx, [edx*3] + lea edx, [ecx+edx*4] + push dword [eax] + pop dword [edx] + mov [eax], edx + pop edx +@@: + mov eax, ecx + xchg eax, [ebp+.FreeList+edx*4] + mov [ecx], eax + pop edx + jmp .gfb5 +.gfb8: + pop ecx + pop eax + mov edx, [ebp+.FreeList+eax*4] + test edx, edx + jz .aur.cont + push edx + mov edx, [edx] + mov [ebp+.FreeList+eax*4], edx + pop eax + ret + +.AllocContext: +; CSubAllocator::AllocContext + mov eax, [ebp+.HiUnit] + cmp eax, [ebp+.LoUnit] + jz @f + sub eax, .UNIT_SIZE + mov [ebp+.HiUnit], eax + ret +@@: + mov eax, [ebp+.FreeList] + test eax, eax + jz @f + mov edx, [eax] + mov [ebp+.FreeList], edx + ret +@@: + xor eax, eax + jmp .AllocUnitsRare + +.AllocUnits: +; CSubAllocator::AllocUnits(ecx) + movzx ecx, [.Units2Indx+ecx-1] + mov eax, [ebp+.FreeList+ecx*4] + test eax, eax + jz @f + mov edx, [eax] + mov [ebp+.FreeList+ecx*4], edx + ret +@@: + mov eax, [ebp+.LoUnit] + movzx edx, [.Indx2Units+ecx] + lea edx, [edx*3] + lea eax, [eax+edx*4] + cmp eax, [ebp+.HiUnit] + ja @f + xchg eax, [ebp+.LoUnit] + ret +@@: + mov eax, ecx + +.AllocUnitsRare: +; CSubAllocator::AllocUnitsRare(eax) + cmp [ebp+.GlueCount], 0 + jz .GlueFreeBlocks +.aur.cont: + push eax +.aur1: + inc eax + cmp eax, .N_INDEXES + jz .aur3 + mov edx, [ebp+.FreeList+eax*4] + test edx, edx + jz .aur1 + push edx + mov edx, [edx] + mov [ebp+.FreeList+eax*4], edx + call .SplitBlock + pop eax + pop edx + ret +.aur3: + dec [ebp+.GlueCount] + pop eax + movzx eax, [.Indx2Units+eax] + lea edx, [eax*3] + shl edx, 2 + mov eax, [ebp+.UnitsStart] + sub eax, [ebp+.pText] + cmp eax, edx + jbe .aur4 + mov eax, [ebp+.UnitsStart] + sub eax, edx + mov [ebp+.UnitsStart], eax + ret +.aur4: + xor eax, eax + ret + +.SplitBlock: +; CSubAllocator::SplitBlock(pv=[esp+4],oldIndx=eax,newIndx=[esp+8]) + push eax + mov edx, [esp+12] + movzx eax, [.Indx2Units+eax] + movzx edx, [.Indx2Units+edx] + sub eax, edx + lea edx, [edx*3] + push ecx + mov ecx, [esp+12] + lea ecx, [ecx+edx*4] + movzx edx, [.Units2Indx+eax-1] + cmp [.Indx2Units+edx], al + jz .aur2 + push dword [ebp+.FreeList+(edx-1)*4] + pop dword [ecx] + mov [ebp+.FreeList+(edx-1)*4], ecx + movzx edx, [.Indx2Units+edx-1] + sub eax, edx + lea edx, [edx*3] + lea ecx, [ecx+edx*4] +.aur2: + movzx eax, [.Units2Indx+eax-1] + push dword [ebp+.FreeList+eax*4] + pop dword [ecx] + mov [ebp+.FreeList+eax*4], ecx + pop ecx + pop eax + ret + +.ExpandUnits: +; CSubAllocator::ExpandUnits(void* oldPtr=esi, int oldNU=eax) + push edx + movzx edx, [.Units2Indx + eax - 1] + cmp dl, [.Units2Indx + eax] + jnz @f + pop edx + mov eax, esi + ret +@@: + push eax ecx edx + lea ecx, [eax+1] + call .AllocUnits + pop edx + test eax, eax + jz @f + push esi edi + mov edi, eax + mov ecx, [esp+8+4] + lea ecx, [ecx*3] + rep movsd + pop edi esi + mov ecx, [ebp+.FreeList+edx*4] + mov [esi], ecx + mov [ebp+.FreeList+edx*4], esi +@@: + pop ecx + add esp, 4 + pop edx + ret + +.ShrinkUnits: +; CSubAllocator::ShrinkUnits(void* oldPtr=eax, int oldNU=ebx, int newNU=ecx) + push ecx + movzx ebx, [.Units2Indx+ebx-1] + movzx ecx, [.Units2Indx+ecx-1] + cmp ebx, ecx + jnz @f + pop ecx + ret +@@: + mov edx, [ebp+.FreeList+ecx*4] + test edx, edx + jz @f + push dword [edx] + pop [ebp+.FreeList+ecx*4] + pop ecx + push esi edi + mov esi, eax + mov edi, edx + lea ecx, [ecx*3] + rep movsd + pop edi esi + mov ecx, [ebp+.FreeList+ebx*4] + mov [eax], ecx + mov [ebp+.FreeList+ebx*4], eax + mov eax, edx + ret +@@: + push ecx + push eax + mov eax, ebx + call .SplitBlock + pop eax + pop ecx + pop ecx + ret + +.FreeUnits: +; CSubAllocator::FreeUnits(void* ptr=eax, int oldNU=ebx) + movzx ebx, [.Units2Indx+ebx-1] + push [ebp+.FreeList+ebx*4] + pop dword [eax] + mov [ebp+.FreeList+ebx*4], eax + ret + +ppmd_get_buf_size: + cmp dword [esi-4], 5 + jb return.err + lodsb + lodsd + cmp eax, ppmd_decoder.kMaxMemBlockSize + ja return.err + add eax, ppmd_decoder.basesize + ppmd_decoder.kExtraSize + mov edx, 0x4000 + ret + +ppmd_init_decoder: + mov [ebp+ppmd_decoder.bInited], 0 +; CDecoder::SetDecoderProperties2 + lodsb + mov [ebp+ppmd_decoder.order], al + lodsd + mov [ebp+ppmd_decoder.usedMemorySize], eax +; CSubAllocator::CSubAllocator + xor eax, eax + mov [ebp+ppmd_decoder.GlueCount], al + lea edi, [ebp+ppmd_decoder.LoUnit] + mov ecx, (ppmd_decoder.SEE2Cont - ppmd_decoder.LoUnit)/4 + rep stosd +; CSubAllocator::StartSubAllocator + lea eax, [ebp+ppmd_decoder.Base+ppmd_decoder.UNIT_SIZE] + mov [ebp+ppmd_decoder.HeapStart], eax + mov [ebp+streamInfo.fillBuf], ppmd_decoder.fillBuf + ret diff --git a/programs/fs/kfar/trunk/kfar_arc/sha256.inc b/programs/fs/kfar/trunk/kfar_arc/sha256.inc new file mode 100644 index 0000000000..a039141f26 --- /dev/null +++ b/programs/fs/kfar/trunk/kfar_arc/sha256.inc @@ -0,0 +1,238 @@ +; Implementation of SHA-256 hash algorithm. +; Written by diamond in 2007. + +iglobal +align 4 +sha256_start_digest: + dd 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A + dd 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +sha256_const: + dd 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5 + dd 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5 + dd 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3 + dd 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174 + dd 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC + dd 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA + dd 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7 + dd 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967 + dd 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13 + dd 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85 + dd 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3 + dd 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070 + dd 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5 + dd 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3 + dd 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208 + dd 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 +endg + +uglobal +align 4 +sha256_buf rb 64 +sha256_digest rd 8 +sha256_count dd ? +sha256_size dq ? +endg + +sha256_init: + mov edi, sha256_digest + mov esi, sha256_start_digest + push 8 + pop ecx + rep movsd + xor eax, eax + stosd ; 0 bytes in buffer + stosd + stosd ; 0 bytes processed + ret + +; Core of SHA-256: transform 64-byte 'sha256_buf' to updated 'sha256_digest' +sha256_transform: + mov esi, sha256_buf + mov edi, esi +rept 16 +{ + lodsd + bswap eax + stosd +} + push ebp + mov ebp, [esi+7*4] + mov edi, [esi+6*4] + push dword [esi+5*4] + push dword [esi+4*4] + push dword [esi+3*4] + push dword [esi+2*4] + push dword [esi+1*4] + push dword [esi+0*4] + xor ecx, ecx +.loop: +macro cmd1 cmd,a,b +{ +if (b and 7) = 7 + cmd a, ebp +else if (b and 7) = 6 + cmd a, edi +else + cmd a, [esp+(b and 7)*4] +end if +} +macro cmd2 cmd,a,b +{ +if (a and 7) = 7 + cmd ebp, b +else if (a and 7) = 6 + cmd edi, b +else + cmd [esp+(a and 7)*4], b +end if +} +rept 16 counter +{ +cmd1 mov, eax, (5-counter) + ror eax, 6 + mov edx, eax + ror eax, 5 + xor edx, eax + ror eax, 14 + xor edx, eax +cmd1 mov, eax, (6-counter) +cmd1 mov, esi, (7-counter) + xor eax, esi +cmd1 and, eax, (5-counter) + xor eax, esi + add edx, eax + add edx, [sha256_const+ecx+(counter-1)*4] + add edx, dword [sha256_buf+(counter-1)*4] + test ecx, ecx + jz @f + mov eax, dword [sha256_buf+((counter-3) and 15)*4] + mov esi, eax + ror eax, 17 + shr esi, 10 + xor esi, eax + ror eax, 2 + xor esi, eax + add esi, dword [sha256_buf+((counter-8) and 15)*4] + mov eax, dword [sha256_buf+(counter and 15)*4] + mov ebx, eax + ror eax, 7 + shr ebx, 3 + xor ebx, eax + ror eax, 11 + xor ebx, eax + add esi, ebx + add dword [sha256_buf+(counter-1)*4], esi + add edx, esi +@@: +cmd1 add, edx, (8-counter) +cmd2 mov, (8-counter), edx +cmd2 add, (4-counter), edx +cmd1 mov, ebx, (1-counter) + mov eax, ebx +cmd1 mov, edx, (2-counter) + mov esi, ebx + ror eax, 2 + or esi, edx + and ebx, edx +cmd1 and, esi, (3-counter) + mov edx, eax + or esi, ebx + ror eax, 11 + xor edx, eax + ror eax, 9 + xor edx, eax + add esi, edx +cmd2 add, (8-counter), esi +} +purge cmd1,cmd2 + add cl, 64 + jnz .loop + mov esi, sha256_digest + pop eax + add [esi+0*4], eax + pop eax + add [esi+1*4], eax + pop eax + add [esi+2*4], eax + pop eax + add [esi+3*4], eax + pop eax + add [esi+4*4], eax + pop eax + add [esi+5*4], eax + add [esi+6*4], edi + add [esi+7*4], ebp + pop ebp + ret + +sha256_update.transform: + push esi edx + call sha256_transform + pop edx esi + mov [sha256_count], ecx + +sha256_update: +; in: esi->data, edx=size + mov eax, 64 + sub eax, [sha256_count] + sub eax, edx + sbb ecx, ecx + and ecx, eax + add ecx, edx + sub edx, ecx + mov edi, sha256_buf + add edi, [sha256_count] + add [sha256_count], ecx + add dword [sha256_size], ecx + adc dword [sha256_size+4], 0 + rep movsb + cmp edi, sha256_buf+64 + jz .transform +.ret: + ret + +sha256_final: +; out: edi->digest + push edi + mov eax, [sha256_count] + mov [sha256_buf+eax], 0x80 + inc eax + cmp al, 64-8 + jbe @f + lea edi, [sha256_buf+eax] + push 64 + pop ecx + sub ecx, eax + xor eax, eax + rep stosb + push edx + call sha256_transform + pop edx + xor eax, eax +@@: + push 64-8 + pop ecx + sub ecx, eax + lea edi, [sha256_buf+eax] + xor eax, eax + rep stosb + mov eax, dword [sha256_size] + mov edx, dword [sha256_size+4] + shld edx, eax, 3 + shl eax, 3 + bswap edx + bswap eax + xchg eax, edx + stosd + xchg eax, edx + stosd + call sha256_transform + mov esi, sha256_digest + mov cl, 8 + pop edi +@@: + lodsd + bswap eax + stosd + loop @b + ret diff --git a/programs/fs/kfar/trunk/tools.inc b/programs/fs/kfar/trunk/tools.inc index 1f4d868daa..d039f4c0ca 100644 --- a/programs/fs/kfar/trunk/tools.inc +++ b/programs/fs/kfar/trunk/tools.inc @@ -1,3 +1,12 @@ +CHECK_FOR_LEAKS = 0 +if CHECK_FOR_LEAKS +uglobal +allocatedregions rd 1024 +endg +iglobal +numallocatedregions dd 0 +endg +end if pgalloc: ; in: ecx=size ; out: eax=pointer or NULL @@ -7,12 +16,50 @@ pgalloc: push 12 pop ebx int 0x40 +if CHECK_FOR_LEAKS + test eax, eax + jz .no +.b: + mov ebx, [numallocatedregions] + cmp ebx, 1024 + jb @f + int3 + jmp $ +@@: + mov [allocatedregions+ebx*4], eax + inc [numallocatedregions] +.no: +end if pop ebx ret pgfree: ; in: ecx=pointer ; destroys eax +if CHECK_FOR_LEAKS + jecxz .no + mov eax, [numallocatedregions] +@@: + dec eax + js .a + cmp [allocatedregions+eax*4], ecx + jnz @b + jmp @f +.a: + int3 + jmp $ +@@: + dec [numallocatedregions] +@@: + cmp eax, [numallocatedregions] + jae @f + push [allocatedregions+eax*4+4] + pop [allocatedregions+eax*4] + inc eax + jmp @b +@@: +.no: +end if push ebx push 68 pop eax @@ -31,6 +78,29 @@ pgrealloc: push 20 pop ebx int 0x40 +if CHECK_FOR_LEAKS + test edx, edx + jz pgalloc.b + test eax, eax + jz .no + cmp eax, edx + jz .no + xor ebx, ebx +@@: + cmp ebx, [numallocatedregions] + jae .a + cmp [allocatedregions+ebx*4], edx + jz @f + inc ebx + jmp @b +@@: + mov [allocatedregions+ebx*4], eax + jmp .no +.a: + int3 + jmp $ +.no: +end if pop ebx ret @@ -52,6 +122,17 @@ xpgrealloc: call pgrealloc jmp xpgalloc.common +getfreemem: +; out: eax=size of free RAM in Kb + push ebx + push 18 + pop eax + push 16 + pop ebx + int 0x40 + pop ebx + ret + get_error_msg: ; in: eax=error code ; out: eax=pointer to message (in static buffer) @@ -85,6 +166,7 @@ get_error_msg: test al, al jnz @b pop eax + dec edi push edx ecx test eax, eax jns @f @@ -162,7 +244,8 @@ load_dll_and_import: pop eax pop esi jz .do - push eax +.big: + push esi mov edi, aFileNameTooBig .sayerr: push dword aCannotLoadDLL @@ -173,9 +256,6 @@ load_dll_and_import: push 1 push eax push 3 - push -1 - push -1 - push dword aError call SayErr add esp, 16 xor eax, eax @@ -192,9 +272,15 @@ load_dll_and_import: mov edi, aInvalidDLL test eax, eax jz .sayerr + mov edx, eax + cmp ebp, -1 + jnz @f + pop eax + xor eax, eax + ret +@@: ; initialize import mov edi, aMissingExport - mov edx, eax .import_loop: lodsd test eax, eax diff --git a/programs/fs/kfar/trunk/viewer.inc b/programs/fs/kfar/trunk/viewer.inc index 7bf9891733..af0678f742 100644 --- a/programs/fs/kfar/trunk/viewer.inc +++ b/programs/fs/kfar/trunk/viewer.inc @@ -6,6 +6,9 @@ viewer_data: .buf_pos dd ? .buf_size dd ? .col dq ? + .hPlugin dd ? + .hFile dd ? + .hWorkFile dd ? .encoding db ? .bEofReached db ? .flags db ? ; & 1: hex mode @@ -13,6 +16,7 @@ viewer_data: ; & 4: big-endian unicode rb 1 .filename rb 1024 + .hostname rb 1024 .buf rb 16384 .size = $ end virtual @@ -34,6 +38,30 @@ view_file: jnz @f ret @@: + mov eax, dword [esi+panel1_hPlugin-panel1_dir] + mov [ebp+viewer_data.hPlugin], eax + test eax, eax + jz .nocopyhostname + lea edi, [ebp+viewer_data.hostname] + push esi + mov eax, dword [esi+panel1_parents-panel1_dir] + mov esi, dword [esi+panel1_parents_sz-panel1_dir] + add esi, eax +@@: + dec esi + cmp byte [esi-1], 0 + jz @f + cmp byte [esi-1], '/' + jnz @b +@@: + lodsb + stosb + test al, al + jnz @b + pop esi +.nocopyhostname: + mov eax, dword [esi+panel1_hFile-panel1_dir] + mov [ebp+viewer_data.hFile], eax mov [ebp+viewer_data.encoding], encodings.cp866 mov [ebp+viewer_data.flags], 0 and dword [ebp+viewer_data.col], 0 @@ -48,6 +76,8 @@ view_file: jmp @b @@: lea esi, [ecx+40] + cmp byte [edi-1], '/' + jz @f mov al, '/' stosb @@: @@ -60,9 +90,21 @@ view_file: mov ebx, attrinfo mov [ebx+21], eax .attr_retry: + mov edx, [ebp+viewer_data.hPlugin] + test edx, edx + jz .attr_native + push ebp + push dword [ebx+16] + push eax + push [ebp+viewer_data.hFile] + call [edx+PluginInfo.getattr] + pop ebp + jmp .attr_common +.attr_native: push 70 pop eax int 40h +.attr_common: test eax, eax jz @f lea ebx, [ebp+viewer_data.filename] @@ -75,14 +117,12 @@ view_file: push 2 push eax push 3 - push -1 - push -1 - push aError call SayErr add esp, 3*4 mov ebx, attrinfo test eax, eax jz .attr_retry + pop eax jmp delete_active_screen @@: mov eax, dword [attrinfo.attr+32] @@ -102,7 +142,40 @@ view_file: mov [readinfo.data], eax mov [ebp+viewer_data.buf_pos], eax pop dword [readinfo.name] + mov eax, [ebp+viewer_data.hPlugin] + test eax, eax + jz .retry + push ebx ebp + push O_READ + push dword [readinfo.name] + push [ebp+viewer_data.hFile] + call [eax+PluginInfo.open] + pop ebp ebx + mov [ebp+viewer_data.hWorkFile], eax + test eax, eax + jnz .retry + push ContinueBtn + push 1 + push aCannotOpenFile_ptr + push 1 + call SayErr + jmp delete_active_screen .retry: + mov eax, [ebp+viewer_data.hPlugin] + test eax, eax + jz .read_native + push ebp + push 16384 + push [ebx+readinfo.data-readinfo] + push [ebp+viewer_data.hWorkFile] + call [eax+PluginInfo.read] + pop ebp + cmp eax, -1 + jz .readok ; let's hope that plugin says error itself + mov [ebp+viewer_data.buf_size], eax + mov ebx, eax + jmp .readok +.read_native: push 70 pop eax int 40h @@ -111,6 +184,7 @@ view_file: jz .readok cmp eax, 6 jz .readok +.readerr: lea ebx, [ebp+viewer_data.filename] push ebx push aCannotReadFile @@ -121,9 +195,6 @@ view_file: push 2 push eax push 3 - push -1 - push -1 - push aError call SayErr add esp, 3*4 mov ebx, readinfo @@ -194,6 +265,21 @@ viewer_get_next_char: mov [readinfo.name], eax .readretry: mov ebx, readinfo + mov eax, [ebp+viewer_data.hPlugin] + test eax, eax + jz .native + push ecx ebp + push 8192 + push [ebx+readinfo.data-readinfo] + push [ebp+viewer_data.hWorkFile] + call [eax+PluginInfo.read] + pop ebp ecx + mov ebx, eax + cmp eax, -1 + jnz .readok + xor ebx, ebx + jmp .readok +.native: push 70 pop eax int 40h @@ -201,6 +287,7 @@ viewer_get_next_char: jz .readok cmp eax, 6 jz .readok +.readerr: call ask_retry_ignore jz .readretry .readok: @@ -976,16 +1063,7 @@ viewer_seek: mov [ebx+16], eax lea eax, [ebp+viewer_data.filename] mov [ebx+21], eax - push 70 - pop eax - int 40h - test eax, eax - jz .readok - cmp eax, 6 - jz .readok - call ask_retry_ignore - jz .doread -.readok: + call .q cmp ebx, [readinfo.size] jnz @f add ebx, [ebp+viewer_data.buf_size] @@ -1027,22 +1105,47 @@ viewer_seek: mov [ebx+12], eax lea eax, [ebp+viewer_data.filename] mov [ebx+21], eax + call .q + sub ebx, [readinfo.size] + add ebx, 16384 + jmp .ret + +.q: + mov ebx, readinfo + mov eax, [ebp+viewer_data.hPlugin] + test eax, eax + jz .native + push ebp + push dword [ebx+12] + push dword [ebx+16] + push [ebp+viewer_data.hWorkFile] + push eax + push dword [ebx+8] + push dword [ebx+4] + push [ebp+viewer_data.hWorkFile] + call [eax+PluginInfo.setpos] + pop eax + call [eax+PluginInfo.read] + pop ebp + mov ebx, eax + cmp eax, -1 + jnz @f + xor ebx, ebx @@: + ret +.native: push 70 pop eax int 40h test eax, eax - jz @f + jz .readok cmp eax, 6 - jz @f + jz .readok +.readerr: call ask_retry_ignore - jnz @f - mov ebx, readinfo - jmp @b -@@: - sub ebx, [readinfo.size] - add ebx, 16384 - jmp .ret + jz .q +.readok: + ret ask_retry_ignore: push esi @@ -1056,9 +1159,6 @@ ask_retry_ignore: push 2 push eax push 3 - push -1 - push -1 - push aError call SayErr add esp, 3*4 pop esi @@ -1268,12 +1368,33 @@ viewer_OnRedraw: call viewer_draw_text ret +viewer_OnExit: + mov edx, [ebp+viewer_data.hPlugin] + test edx, edx + jz @f + and [ebp+viewer_data.hPlugin], 0 + push edx ebp + push [ebp+viewer_data.hWorkFile] + call [edx+PluginInfo.close] + pop ebp edx + mov ebx, [ebp+viewer_data.hFile] + call close_handle_if_unused +@@: + ret + +viewer_IsHandleUsed: + cmp edx, [ebp+viewer_data.hPlugin] + jnz @f + cmp ebx, [ebp+viewer_data.hFile] +@@: + ret + viewer_OnKey: mov esi, viewer_ctrlkeys jmp process_ctrl_keys .exit: - call delete_active_screen - ret + call viewer_OnExit + jmp delete_active_screen .down: cmp [ebp+viewer_data.bEofReached], 0 jnz .ret @@ -1459,6 +1580,25 @@ else stosb end if sub ecx, 13 + cmp [ebp+viewer_data.hPlugin], 0 + jz .native + lea esi, [ebp+viewer_data.hostname] + push ecx edi + shr ecx, 1 +@@: + lodsb + test al, al + jz @f + stosb + loop @b +@@: + sub edi, [esp] + sub [esp+4], edi + add [esp], edi + pop edi ecx + lea esi, [ebp+viewer_data.filename] + jmp .main +.native: lea esi, [ebp+viewer_data.filename] push 3 pop edx @@ -1466,10 +1606,13 @@ end if lodsb stosb dec ecx + test al, al + jz .ret cmp al, '/' jnz @b dec edx jnz @b +.main: push esi @@: lodsb @@ -1493,4 +1636,5 @@ end if stosb test al, al jnz @b +.ret: ret