Rev 631 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
589 | diamond | 1 | ; |
2 | ; project name: KFar_Arc - plugin for KFar, which supports various archives |
||
3 | ; target platform: KolibriOS |
||
4 | ; compiler: FASM 1.67.14 |
||
5 | ; version: 0.1 |
||
6 | ; last update: 2007-07-11 (Jul 11, 2007) |
||
7 | ; minimal KFar version: 0.4 |
||
8 | ; minimal kernel: no limit |
||
9 | ; |
||
10 | ; author: Diamond |
||
11 | ; email: diamondz@land.ru |
||
12 | ; web: http://diamondz.land.ru |
||
13 | ; |
||
14 | |||
15 | ; standard start of Kolibri dynamic library |
||
16 | format MS COFF |
||
17 | public EXPORTS |
||
18 | |||
19 | section '.flat' code readable align 16 |
||
20 | |||
21 | ; include auxiliary procedures |
||
22 | include 'kglobals.inc' ; iglobal/uglobal |
||
23 | include 'lang.inc' ; define language for localized strings |
||
24 | include 'crc.inc' ; CRC32 calculation |
||
25 | include 'sha256.inc' ; SHA-256 hash algorithm |
||
26 | include 'aes.inc' ; AES crypto algorithm |
||
27 | ; include main code for archives loading |
||
28 | include '7z.inc' ; *.7z |
||
29 | include 'lzma.inc' ; LZMA-decoder for *.7z |
||
30 | include 'ppmd.inc' ; PPMD-decoder for *.7z |
||
31 | include '7zbranch.inc' ; branch filters for *.7z |
||
32 | include '7zaes.inc' ; AES cryptor for *.7z |
||
33 | |||
34 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
35 | ;;;;;;;;;;;;;;; Interface for KFar ;;;;;;;;;;;;;; |
||
36 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
37 | virtual at 0 |
||
38 | kfar_info_struc: |
||
39 | .lStructSize dd ? |
||
40 | .kfar_ver dd ? |
||
41 | .open dd ? |
||
42 | .read dd ? |
||
43 | .write dd ? |
||
44 | .seek dd ? |
||
45 | .flush dd ? |
||
46 | .filesize dd ? |
||
47 | .close dd ? |
||
48 | .pgalloc dd ? |
||
49 | .pgrealloc dd ? |
||
50 | .pgfree dd ? |
||
51 | .getfreemem dd ? |
||
52 | .pgalloc2 dd ? |
||
53 | .pgrealloc2 dd ? |
||
54 | .pgfree2 dd ? |
||
55 | .menu dd ? |
||
56 | .menu_centered_in dd ? |
||
57 | .DialogBox dd ? |
||
58 | .SayErr dd ? |
||
59 | .Message dd ? |
||
60 | .cur_console_size dd ? |
||
61 | end virtual |
||
62 | |||
63 | ; int __stdcall plugin_load(kfar_info* info); |
||
64 | ; Initialization of plugin + Save used KFar functions. |
||
65 | plugin_load: |
||
66 | mov eax, [esp+4] |
||
67 | mov [kfar_info], eax |
||
68 | push [eax+kfar_info_struc.read] |
||
69 | pop [read] |
||
70 | push [eax+kfar_info_struc.seek] |
||
71 | pop [seek] |
||
72 | push [eax+kfar_info_struc.close] |
||
73 | pop [close] |
||
74 | lea esi, [eax+kfar_info_struc.DialogBox] |
||
75 | mov edi, DialogBox |
||
76 | movsd |
||
77 | movsd |
||
78 | movsd |
||
79 | movsd |
||
80 | lea esi, [eax+kfar_info_struc.pgalloc] |
||
81 | mov edi, pgalloc |
||
82 | movsd |
||
83 | movsd |
||
84 | movsd |
||
85 | movsd |
||
86 | call init_crc_table |
||
87 | call init_aes |
||
88 | call init_ppmd |
||
89 | xor eax, eax ; success |
||
90 | ret 4 |
||
91 | |||
92 | ; HANDLE __stdcall OpenFilePlugin(HANDLE basefile, const char* name, |
||
93 | ; const void* attr, const void* data, int datasize); |
||
94 | ; This function is called when user presses Enter (or Ctrl+PgDn) on file. |
||
95 | ; Plugin tests whether given file is of supported type |
||
96 | ; and if so, loads information and returns |
||
97 | ; handle to be used in subsequent calls to ReadFolder, SetFolder and so on. |
||
98 | OpenFilePlugin: |
||
99 | mov [bPasswordDefined], 0 |
||
100 | mov esi, [esp+16] |
||
101 | mov ebp, [esp+4] |
||
102 | ; test for 7z archive |
||
103 | cmp dword [esp+20], 20h ; minimal size of 7z archive is 20h bytes |
||
104 | jb .no_7z |
||
105 | cmp word [esi], '7z' ; signature, part 1 |
||
106 | jnz .no_7z |
||
107 | cmp dword [esi+2], 0x1C27AFBC ; signature, part 2 |
||
108 | jnz .no_7z |
||
109 | call open_7z |
||
110 | ret 20 |
||
111 | .no_7z: |
||
112 | xor eax, eax |
||
113 | ret 20 |
||
114 | |||
115 | ; Handle of plugin in kfar_arc is as follow: |
||
116 | virtual at 0 |
||
117 | handle_common: |
||
118 | .type dd ? |
||
119 | .root.subfolders dd ? |
||
120 | .root.subfolders.end dd ? |
||
121 | .root.subfiles dd ? |
||
122 | .root.subfiles.end dd ? |
||
123 | .root.NumSubItems dd ? |
||
124 | ; ... some plugin-specific data follows ... |
||
125 | end virtual |
||
126 | |||
127 | ; and for each archive item there is one file info structure, which begins as follow: |
||
128 | virtual at 0 |
||
129 | file_common: |
||
130 | .fullname dd ? ; pointer to cp866 string |
||
131 | .name dd ? ; name without path (end of .fullname) |
||
132 | .namelen dd ? ; strlen(.name) |
||
133 | .bIsDirectory db ? |
||
134 | .bPseudoFolder db ? |
||
135 | rb 2 |
||
136 | .parent dd ? ; pointer to parent directory record |
||
137 | .subfolders dd ? ; head of L2-list of subfolders [for folders] |
||
138 | .subfolders.end dd ? |
||
139 | .subfiles dd ? ; head of L2-list of files [for folders] |
||
140 | .subfiles.end dd ? |
||
141 | .NumSubItems dd ? |
||
142 | .next dd ? ; next item in list of subfolders/files |
||
143 | .prev dd ? ; previous item in list of subfolders/files |
||
144 | end virtual |
||
145 | |||
146 | ; void __stdcall ClosePlugin(HANDLE hPlugin); |
||
147 | ; This function frees all resources allocated in OpenFilePlugin. |
||
148 | ClosePlugin: |
||
149 | mov eax, [esp+4] ; get hPlugin |
||
150 | mov eax, [eax] ; hPlugin is pointer to internal data structure |
||
151 | ; first dword is archive type (type_xxx constants) |
||
152 | dec eax ; types start from 1 |
||
153 | jmp dword [ClosePluginTable+eax*4] |
||
154 | |||
155 | ; int __stdcall ReadFolder(HANDLE hPlugin, |
||
156 | ; unsigned dirinfo_start, unsigned dirinfo_size, void* dirdata); |
||
157 | ReadFolder: |
||
158 | mov eax, [esp+4] |
||
159 | mov eax, [eax] |
||
160 | dec eax |
||
161 | jmp dword [ReadFolderTable+eax*4] |
||
162 | |||
163 | ; bool __stdcall SetFolder(HANDLE hPlugin, |
||
164 | ; const char* relative_path, const char* absolute_path); |
||
165 | SetFolder: |
||
166 | mov eax, [esp+4] |
||
167 | mov eax, [eax] |
||
168 | dec eax |
||
169 | jmp dword [SetFolderTable+eax*4] |
||
170 | |||
171 | ; void __stdcall GetFiles(HANDLE hPlugin, int NumItems, void* items[], |
||
172 | ; void* addfile, void* adddir); |
||
173 | ; bool __stdcall addfile(const char* name, void* bdfe_info, HANDLE hFile); |
||
174 | ; bool __stdcall adddir(const char* name, void* bdfe_info); |
||
175 | GetFiles: |
||
176 | mov ebp, [esp+4] |
||
177 | mov eax, [ebp] |
||
178 | dec eax |
||
179 | jmp dword [GetFilesTable+eax*4] |
||
180 | |||
181 | ; void __stdcall GetOpenPluginInfo(HANDLE hPlugin, OpenPluginInfo* info); |
||
182 | GetOpenPluginInfo: |
||
183 | mov eax, [esp+8] ; get info ptr |
||
184 | mov byte [eax], 3 ; flags: add non-existing '..' entry automatically |
||
185 | ; use GetFiles for copying |
||
186 | ret 8 |
||
187 | |||
188 | ; int __stdcall getattr(HANDLE hPlugin, const char* filename, void* info); |
||
189 | mygetattr: |
||
190 | call lookup_file_name |
||
191 | test eax, eax |
||
192 | jz @f |
||
193 | mov edx, [ebp] |
||
194 | dec edx |
||
195 | mov edi, [esp+12] ; info ptr |
||
196 | call dword [getattrTable+edx*4] |
||
197 | xor eax, eax |
||
198 | ret 12 |
||
199 | @@: |
||
200 | mov al, 5 ; ERROR_FILE_NOT_FOUND |
||
201 | ret 12 |
||
202 | |||
203 | ; HANDLE __stdcall open(HANDLE hPlugin, const char* filename, int mode); |
||
204 | myopen: |
||
205 | call lookup_file_name |
||
206 | test eax, eax |
||
207 | jz @f |
||
208 | mov edx, [ebp] |
||
209 | dec edx |
||
210 | mov edi, [esp+12] ; mode |
||
211 | call dword [openTable+edx*4] |
||
212 | @@: |
||
213 | ret 12 |
||
214 | |||
215 | ; unsigned __stdcall read(HANDLE hFile, void* buf, unsigned size); |
||
216 | myread: |
||
217 | mov ebx, [esp+4] |
||
218 | mov eax, [ebx] |
||
219 | jmp dword [readTable+eax*4] |
||
220 | |||
221 | ; void __stdcall setpos(HANDLE hFile, __int64 pos); |
||
222 | mysetpos: |
||
223 | mov ebx, [esp+4] |
||
224 | mov eax, [ebx] |
||
225 | jmp dword [setposTable+eax*4] |
||
226 | |||
227 | ; void __stdcall close(HANDLE hFile); |
||
228 | myclose: |
||
229 | mov ebx, [esp+4] |
||
230 | mov eax, [ebx] |
||
231 | jmp dword [closeTable+eax*4] |
||
232 | |||
233 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
234 | ;;;;;;;;;;;;;; Auxiliary procedures ;;;;;;;;;;;;; |
||
235 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
236 | |||
237 | ; return.err and return.clear are labels to jmp if something is invalid |
||
238 | ; the caller must previously define [_esp], [_ebp] and [error_proc], [clear_proc] |
||
239 | return.err: |
||
240 | mov esp, [_esp] |
||
241 | mov ebp, [_ebp] |
||
242 | jmp [error_proc] |
||
243 | return.clear: |
||
244 | mov esp, [_esp] |
||
245 | mov ebp, [_ebp] |
||
246 | jmp [clear_proc] |
||
247 | |||
248 | ; data for following routine |
||
249 | iglobal |
||
250 | align 4 |
||
251 | _24 dd 24 |
||
252 | _60 dd 60 |
||
253 | _10000000 dd 10000000 |
||
254 | days400year dd 365*400+100-4+1 |
||
255 | days100year dd 365*100+25-1 |
||
256 | days4year dd 365*4+1 |
||
257 | days1year dd 365 |
||
258 | months dd 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
||
259 | months2 dd 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
||
260 | _400 dd 400 |
||
261 | _100 dd 100 |
||
262 | endg |
||
263 | |||
264 | ; Convert QWORD FILETIME to BDFE format. |
||
265 | ntfs_datetime_to_bdfe: |
||
266 | ; edx:eax = number of 100-nanosecond intervals since January 1, 1601, in UTC |
||
267 | push eax |
||
268 | mov eax, edx |
||
269 | xor edx, edx |
||
270 | div [_10000000] |
||
271 | xchg eax, [esp] |
||
272 | div [_10000000] |
||
273 | pop edx |
||
274 | ; edx:eax = number of seconds since January 1, 1601 |
||
275 | push eax |
||
276 | mov eax, edx |
||
277 | xor edx, edx |
||
278 | div [_60] |
||
279 | xchg eax, [esp] |
||
280 | div [_60] |
||
281 | mov [edi], dl |
||
282 | pop edx |
||
283 | ; edx:eax = number of minutes |
||
284 | div [_60] |
||
285 | mov [edi+1], dl |
||
286 | ; eax = number of hours (note that 2^64/(10^7*60*60) < 2^32) |
||
287 | xor edx, edx |
||
288 | div [_24] |
||
289 | mov [edi+2], dl |
||
290 | mov [edi+3], byte 0 |
||
291 | ; eax = number of days since January 1, 1601 |
||
292 | xor edx, edx |
||
293 | div [days400year] |
||
294 | imul eax, 400 |
||
295 | add eax, 1601 |
||
296 | mov [edi+6], ax |
||
297 | mov eax, edx |
||
298 | xor edx, edx |
||
299 | div [days100year] |
||
300 | cmp al, 4 |
||
301 | jnz @f |
||
302 | dec eax |
||
303 | add edx, [days100year] |
||
304 | @@: |
||
305 | imul eax, 100 |
||
306 | add [edi+6], ax |
||
307 | mov eax, edx |
||
308 | xor edx, edx |
||
309 | div [days4year] |
||
310 | shl eax, 2 |
||
311 | add [edi+6], ax |
||
312 | mov eax, edx |
||
313 | xor edx, edx |
||
314 | div [days1year] |
||
315 | cmp al, 4 |
||
316 | jnz @f |
||
317 | dec eax |
||
318 | add edx, [days1year] |
||
319 | @@: |
||
320 | add [edi+6], ax |
||
321 | push esi edx |
||
322 | mov esi, months |
||
323 | movzx eax, word [edi+6] |
||
324 | test al, 3 |
||
325 | jnz .noleap |
||
326 | xor edx, edx |
||
327 | push eax |
||
328 | div [_400] |
||
329 | pop eax |
||
330 | test edx, edx |
||
331 | jz .leap |
||
332 | xor edx, edx |
||
333 | div [_100] |
||
334 | test edx, edx |
||
335 | jz .noleap |
||
336 | .leap: |
||
337 | mov esi, months2 |
||
338 | .noleap: |
||
339 | pop edx |
||
340 | xor eax, eax |
||
341 | inc eax |
||
342 | @@: |
||
343 | sub edx, [esi] |
||
344 | jb @f |
||
345 | add esi, 4 |
||
346 | inc eax |
||
347 | jmp @b |
||
348 | @@: |
||
349 | add edx, [esi] |
||
350 | pop esi |
||
351 | inc edx |
||
352 | mov [edi+4], dl |
||
353 | mov [edi+5], al |
||
354 | add edi, 8 |
||
355 | ret |
||
356 | |||
357 | ; By given array of files information, initialize links between them |
||
358 | ; ("[folder] contains [item]" relations). |
||
359 | ; Information structure must be compatible with 'file_common'. |
||
360 | ; Size of information structure is in [esp+4]. |
||
361 | init_file_links: |
||
362 | ; in: edx->file infos, ebx = number of files, [esp+4] = size, |
||
363 | ; edi->{dd root.subfolders, dd root.subfolders.end, |
||
364 | ; dd root.subfiles, dd root.subfiles.end, dd root.NumItems} |
||
365 | xor eax, eax |
||
366 | mov [.free], eax |
||
367 | push edi |
||
368 | stosd |
||
369 | stosd |
||
370 | stosd |
||
371 | stosd |
||
372 | stosd |
||
373 | pop edi |
||
374 | ; Loop through all files |
||
375 | .mainloop: |
||
376 | dec ebx |
||
377 | js .mainloopdone |
||
378 | ; Parse file name |
||
379 | ; esi->current character in name |
||
380 | ; dword [esp] = start of current component in file name |
||
381 | ; ecx->{dd curdir.subfolders, dd curdir.subfolders.end, |
||
382 | ; dd curdir.subfiles, dd curdir.subfiles.end} |
||
383 | mov esi, [edx+file_common.fullname] |
||
384 | mov ecx, edi |
||
385 | .parseloop: |
||
386 | push esi |
||
387 | .parsename: |
||
388 | lodsb |
||
389 | test al, al |
||
390 | jz @f |
||
391 | cmp al, '/' |
||
392 | jnz .parsename |
||
393 | @@: |
||
394 | ; we have found next component of current name; look for it in current directory |
||
395 | sub esi, [esp] |
||
396 | dec esi ; esi = strlen(component) |
||
397 | cmp esi, 259 |
||
398 | jbe @f |
||
399 | push ContinueBtn |
||
400 | push 1 |
||
401 | push aNameTooLong_ptr |
||
402 | push 1 |
||
403 | call [SayErr] |
||
404 | jmp return.clear |
||
405 | @@: |
||
406 | push ecx |
||
407 | mov eax, [ecx] ; eax->subfolders list |
||
408 | mov ecx, esi |
||
409 | .scansubfolders: |
||
410 | test eax, eax |
||
411 | jz .nofolder |
||
412 | add eax, [hOut] |
||
413 | cmp [eax+file_common.namelen], ecx |
||
414 | jnz .scancont |
||
415 | mov esi, [esp+4] |
||
416 | push ecx edi |
||
417 | mov edi, [eax+file_common.name] |
||
418 | repz cmpsb |
||
419 | pop edi ecx |
||
420 | jz .subfound |
||
421 | .scancont: |
||
422 | mov eax, [eax+file_common.next] |
||
423 | jmp .scansubfolders |
||
424 | .subfound: |
||
425 | ; found subfolder, set it as current and continue parsing name |
||
426 | add [esp+4], ecx |
||
427 | pop ecx |
||
428 | lea ecx, [eax+file_common.subfolders] |
||
429 | pop esi |
||
430 | lodsb |
||
431 | test al, al |
||
432 | jnz .parseloop |
||
433 | ; that was the last component of the name, and we have found subfolder |
||
434 | ; so found subfolder is a virtual subfolder and must be replaced with current |
||
435 | ; name |
||
436 | mov eax, [ecx-file_common.subfolders+file_common.namelen] |
||
437 | mov [edx+file_common.namelen], eax |
||
438 | sub esi, eax |
||
439 | dec esi |
||
440 | mov [edx+file_common.name], esi |
||
441 | sub edx, [hOut] ; convert pointer to relative |
||
442 | ; replace item in L2-list |
||
443 | mov eax, [ecx-file_common.subfolders+file_common.prev] |
||
444 | test eax, eax |
||
445 | jnz .1 |
||
446 | mov eax, [ecx-file_common.subfolders+file_common.parent] |
||
447 | sub eax, file_common.next - file_common.subfolders |
||
448 | jnc .1 |
||
449 | lea eax, [edi-file_common.next] |
||
450 | jmp .2 |
||
451 | .1: |
||
452 | add eax, [hOut] |
||
453 | .2: |
||
454 | mov [eax+file_common.next], edx |
||
455 | mov eax, [ecx-file_common.subfolders+file_common.next] |
||
456 | test eax, eax |
||
457 | jnz .3 |
||
458 | mov eax, [ecx-file_common.subfolders+file_common.parent] |
||
459 | sub eax, file_common.prev - file_common.subfolders.end |
||
460 | jnc .3 |
||
461 | lea eax, [edi-file_common.prev+4] |
||
462 | jmp .4 |
||
463 | .3: |
||
464 | add eax, [hOut] |
||
465 | .4: |
||
466 | mov [eax+file_common.prev], edx |
||
467 | ; correct parent links in childrens |
||
468 | mov eax, [ecx] |
||
469 | @@: |
||
470 | test eax, eax |
||
471 | jz @f |
||
472 | add eax, [hOut] |
||
473 | mov [eax+file_common.parent], edx |
||
474 | mov eax, [eax+file_common.next] |
||
475 | jmp @b |
||
476 | @@: |
||
477 | mov eax, [ecx+8] |
||
478 | @@: |
||
479 | test eax, eax |
||
480 | jz @f |
||
481 | add eax, [hOut] |
||
482 | mov [eax+file_common.parent], edx |
||
483 | mov eax, [eax+file_common.next] |
||
484 | jmp @b |
||
485 | @@: |
||
486 | add edx, [hOut] |
||
487 | ; set children links |
||
488 | mov eax, [ecx] |
||
489 | mov [edx+file_common.subfolders], eax |
||
490 | mov eax, [ecx+4] |
||
491 | mov [edx+file_common.subfolders.end], eax |
||
492 | mov eax, [ecx+8] |
||
493 | mov [edx+file_common.subfiles], eax |
||
494 | mov eax, [ecx+12] |
||
495 | mov [edx+file_common.subfiles.end], eax |
||
496 | mov eax, [ecx+16] |
||
497 | mov [edx+file_common.NumSubItems], eax |
||
498 | ; set prev/next links |
||
499 | mov eax, [ecx-file_common.subfolders+file_common.next] |
||
500 | mov [edx+file_common.next], eax |
||
501 | mov eax, [ecx-file_common.subfolders+file_common.prev] |
||
502 | mov [edx+file_common.prev], eax |
||
503 | ; add old item to list of free items |
||
504 | uglobal |
||
505 | align 4 |
||
506 | init_file_links.free dd ? |
||
507 | endg |
||
508 | sub ecx, file_common.subfolders |
||
509 | mov eax, [.free] |
||
510 | mov [ecx], eax |
||
511 | sub ecx, [hOut] |
||
512 | mov [.free], ecx |
||
513 | jmp .mainloopcont |
||
514 | .nofolder: |
||
515 | mov eax, edx |
||
516 | mov esi, [esp+4] |
||
517 | cmp byte [esi+ecx], 0 |
||
518 | jz .newitem |
||
519 | ; the current item is as 'dir1/item1' and 'dir1' has not been found |
||
520 | ; allocate virtual subfolder 'dir1' |
||
521 | mov eax, [init_file_links.free] |
||
522 | test eax, eax |
||
523 | jz .realloc |
||
524 | add eax, [hOut] |
||
525 | push dword [eax] |
||
526 | pop [init_file_links.free] |
||
527 | jmp .allocated |
||
528 | .realloc: |
||
529 | ; there is no free space, so reallocate [hOut] block |
||
530 | mov eax, [hOut] |
||
531 | sub [esp], eax ; make pointers relative |
||
532 | sub edx, eax |
||
533 | sub edi, eax |
||
534 | push ecx |
||
535 | mov ecx, [hOut.allocated] |
||
536 | add ecx, [esp+12+4] |
||
537 | mov [hOut.allocated], ecx |
||
538 | push ecx |
||
539 | and ecx, 0xFFF |
||
540 | cmp ecx, [esp+16+4] |
||
541 | pop ecx |
||
542 | ja @f |
||
543 | push edx |
||
544 | mov edx, eax |
||
545 | call [pgrealloc] |
||
546 | pop edx |
||
547 | test eax, eax |
||
548 | jnz @f |
||
549 | mov ecx, [hOut] |
||
550 | call [pgfree] |
||
551 | mov esp, [_esp] |
||
552 | or eax, -1 |
||
553 | ret |
||
554 | @@: |
||
555 | pop ecx |
||
556 | mov [hOut], eax |
||
557 | add [esp], eax ; make pointers absolute |
||
558 | add edx, eax |
||
559 | add edi, eax |
||
560 | add eax, [hOut.allocated] |
||
561 | sub eax, [esp+8+4] |
||
562 | .allocated: |
||
563 | ; eax -> new item |
||
564 | mov [eax+file_common.bIsDirectory], 1 |
||
565 | mov [eax+file_common.bPseudoFolder], 1 |
||
566 | .newitem: |
||
567 | mov [eax+file_common.namelen], ecx |
||
568 | pop ecx |
||
569 | pop esi |
||
570 | ; ecx = parent item, eax = current item |
||
571 | mov [eax+file_common.name], esi |
||
572 | inc dword [ecx+16] ; new item in parent folder |
||
573 | push ecx |
||
574 | ; add new item to end of L2-list |
||
575 | and [eax+file_common.next], 0 |
||
576 | cmp [eax+file_common.bIsDirectory], 0 |
||
577 | jnz @f |
||
578 | add ecx, 8 |
||
579 | @@: |
||
580 | push eax |
||
581 | sub eax, [hOut] |
||
582 | cmp dword [ecx], 0 |
||
583 | jnz @f |
||
584 | mov [ecx], eax |
||
585 | @@: |
||
586 | xchg eax, [ecx+4] |
||
587 | xchg eax, ecx |
||
588 | pop eax |
||
589 | mov [eax+file_common.prev], ecx |
||
590 | jecxz @f |
||
591 | add ecx, [hOut] |
||
592 | sub eax, [hOut] |
||
593 | mov [ecx+file_common.next], eax |
||
594 | add eax, [hOut] |
||
595 | @@: |
||
596 | pop ecx |
||
597 | ; set parent link |
||
598 | and [eax+file_common.parent], 0 |
||
599 | cmp ecx, edi |
||
600 | jz @f |
||
601 | sub ecx, file_common.subfolders |
||
602 | sub ecx, [hOut] |
||
603 | mov [eax+file_common.parent], ecx |
||
604 | @@: |
||
605 | ; set current directory to current item |
||
606 | lea ecx, [eax+file_common.subfolders] |
||
607 | ; if that was not last component, continue parse name |
||
608 | add esi, [eax+file_common.namelen] |
||
609 | lodsb |
||
610 | test al, al |
||
611 | jnz .parseloop |
||
612 | .mainloopcont: |
||
613 | ; continue main loop |
||
614 | add edx, [esp+4] |
||
615 | jmp .mainloop |
||
616 | .mainloopdone: |
||
617 | ; Loop done. |
||
618 | ret 4 |
||
619 | |||
620 | ; This subroutine is called by getattr and open. |
||
621 | ; This subroutine looks for file name and returns NULL or pointer to file info record. |
||
622 | lookup_file_name: |
||
623 | mov ebp, [esp+8] ; hPlugin |
||
624 | mov esi, [esp+12] ; filename |
||
625 | lea edi, [ebp+handle_common.root.subfolders] |
||
626 | xor eax, eax |
||
627 | ; KFar operates with absolute names, skip first '/' |
||
628 | cmp byte [esi], '/' |
||
629 | jnz .notfound |
||
630 | inc esi |
||
631 | .mainloop: |
||
632 | ; get next component of name |
||
633 | push -1 |
||
634 | pop ecx |
||
635 | @@: |
||
636 | inc ecx |
||
637 | cmp byte [esi+ecx], '/' |
||
638 | jz @f |
||
639 | cmp byte [esi+ecx], 0 |
||
640 | jnz @b |
||
641 | @@: |
||
642 | ; esi->component, ecx=length |
||
643 | ; scan for required item in subfolders list |
||
644 | push -1 |
||
645 | mov eax, [edi] ; .subfolders |
||
646 | .scan1: |
||
647 | test eax, eax |
||
648 | jz .notfound1 |
||
649 | add eax, ebp |
||
650 | cmp [eax+file_common.namelen], ecx |
||
651 | jnz .cont1 |
||
652 | push ecx esi edi |
||
653 | mov edi, [eax+file_common.name] |
||
654 | repz cmpsb |
||
655 | pop edi esi ecx |
||
656 | jz .found1 |
||
657 | .cont1: |
||
658 | mov eax, [eax+file_common.next] |
||
659 | jmp .scan1 |
||
660 | .notfound1: |
||
661 | pop edx |
||
662 | ; if this is last component in file name, scan in subfiles list |
||
663 | cmp byte [esi+ecx], al |
||
664 | jnz .notfound |
||
665 | inc edx |
||
666 | jnz .notfound |
||
667 | mov eax, [edi+8] ; .subfiles |
||
668 | push edx |
||
669 | jmp .scan1 |
||
670 | .found1: |
||
671 | pop edi |
||
672 | ; item is found, go to next component |
||
673 | lea edi, [eax+file_common.subfolders] |
||
674 | lea esi, [esi+ecx+1] |
||
675 | cmp byte [esi-1], 0 |
||
676 | jnz .mainloop |
||
677 | ; this was the last component |
||
678 | .notfound: |
||
679 | ret |
||
680 | |||
681 | ; Memory streams handling. |
||
682 | ; Archive handlers create memory stream for small files: |
||
683 | ; size of which is not greater than (free RAM size)/4 and |
||
684 | ; not greater than following constant... |
||
685 | ;LIMIT_FOR_MEM_STREAM = 2*1024*1024 |
||
686 | ; ...if it is defined. Now the definition is commented: |
||
687 | ; if user has many physical memory, why not to use it? |
||
688 | |||
689 | virtual at 0 |
||
690 | mem_stream: |
||
691 | .type dd ? ; type_mem_stream |
||
692 | .size dd ? |
||
693 | .pos dd ? |
||
694 | .buf: |
||
695 | end virtual |
||
696 | |||
697 | ; unsigned __stdcall read(ebx = HANDLE hFile, void* buf, unsigned size); |
||
698 | read_mem_stream: |
||
699 | mov eax, [esp+12] |
||
700 | mov ecx, [ebx+mem_stream.size] |
||
701 | sub ecx, [ebx+mem_stream.pos] |
||
702 | jnc @f |
||
703 | xor ecx, ecx |
||
704 | @@: |
||
705 | cmp eax, ecx |
||
706 | jb @f |
||
707 | mov eax, ecx |
||
708 | @@: |
||
709 | mov ecx, eax |
||
710 | lea esi, [ebx+mem_stream.buf] |
||
711 | add esi, [ebx+mem_stream.pos] |
||
712 | add [ebx+mem_stream.pos], eax |
||
713 | mov edi, [esp+8] |
||
714 | mov edx, ecx |
||
715 | shr ecx, 2 |
||
716 | rep movsd |
||
717 | mov ecx, edx |
||
718 | and ecx, 3 |
||
719 | rep movsb |
||
720 | ret 12 |
||
721 | |||
722 | ; void __stdcall setpos(ebx = HANDLE hFile, __int64 pos); |
||
723 | setpos_mem_stream: |
||
724 | mov eax, [esp+8] |
||
725 | mov [ebx+mem_stream.pos], eax |
||
726 | ret 12 |
||
727 | |||
728 | ; void __stdcall close(ebx = HANDLE hFile); |
||
729 | close_mem_stream: |
||
730 | mov ecx, ebx |
||
731 | call [pgfree] |
||
732 | ret 4 |
||
733 | |||
734 | ; Allocate handle for file |
||
735 | ; esi -> handle table, ecx = size of handle |
||
736 | alloc_handle: |
||
737 | ; Handle table is L2-list of allocated pages. |
||
738 | ; Scan for free entry |
||
739 | mov edx, esi |
||
740 | @@: |
||
741 | mov edx, [edx] |
||
742 | cmp edx, esi |
||
743 | jz .alloc_new |
||
744 | mov eax, [edx+8] ; head of L1-list of free entries |
||
745 | test eax, eax ; has free entry? |
||
746 | jz @b |
||
747 | ; we have found allocated page with free entry; allocate entry and return |
||
748 | inc dword [edx+12] ; number of busy entries |
||
749 | push dword [eax] |
||
750 | pop dword [edx+8] |
||
751 | .ret: |
||
752 | ret |
||
753 | .alloc_new: |
||
754 | ; no free pages; get new page and initialize |
||
755 | push ecx |
||
756 | mov ecx, 0x1000 |
||
757 | call [pgalloc] |
||
758 | pop ecx |
||
759 | test eax, eax |
||
760 | jz .ret |
||
761 | ; insert new page to start of L2-list |
||
762 | mov edx, [esi] |
||
763 | mov [eax], edx |
||
764 | mov [esi], eax |
||
765 | mov [eax+4], esi |
||
766 | mov [edx+4], eax |
||
767 | mov dword [eax+12], 1 ; 1 allocated entry |
||
768 | ; initialize list of free entries |
||
769 | lea edx, [eax+16] |
||
770 | push edx ; save return value |
||
771 | add edx, ecx |
||
772 | mov [eax+8], edx |
||
773 | add eax, 0x1000 |
||
774 | @@: |
||
775 | mov esi, edx |
||
776 | add edx, ecx |
||
777 | mov [esi], edx |
||
778 | cmp edx, eax |
||
779 | jb @b |
||
780 | and dword [esi], 0 |
||
781 | pop eax |
||
782 | ret |
||
783 | |||
784 | ; Free handle allocated in previous procedure |
||
785 | ; esi = handle |
||
786 | free_handle: |
||
787 | mov ecx, esi |
||
788 | and ecx, not 0xFFF ; get page |
||
789 | ; add entry to head of L1-list of free entries |
||
790 | mov eax, [ecx+8] |
||
791 | mov [esi], eax |
||
792 | mov [ecx+8], esi |
||
793 | dec dword [ecx+12] ; decrement number of allocated entries |
||
794 | jnz .ret |
||
795 | ; delete page from common L2-list |
||
796 | mov eax, [ecx] |
||
797 | mov edx, [ecx+4] |
||
798 | mov [eax+4], edx |
||
799 | mov [edx], eax |
||
800 | ; free page |
||
801 | call [pgfree] |
||
802 | .ret: |
||
803 | ret |
||
804 | |||
805 | ; Ask user to enter password. |
||
806 | ; Out: ZF set <=> user pressed Esc |
||
807 | ; 'password_ansi', 'password_unicode', 'password_size' filled |
||
808 | query_password: |
||
809 | cmp [bPasswordDefined], 0 |
||
810 | jnz .ret |
||
811 | mov edi, password_data |
||
812 | mov eax, password_maxlen |
||
813 | stosd ; maximum length |
||
814 | xor eax, eax |
||
815 | stosd ; start of visible part |
||
816 | stosd ; position of cursor |
||
817 | stosb ; initial state: empty string |
||
818 | mov eax, [cur_console_size] |
||
819 | mov eax, [eax] ; get current console width |
||
820 | sub eax, 12 |
||
821 | mov edi, password_dlg |
||
822 | mov [edi+password_dlg.width-password_dlg], eax |
||
823 | dec eax |
||
824 | dec eax |
||
825 | mov [edi+password_dlg.width1-password_dlg], eax |
||
826 | mov [edi+password_dlg.width2-password_dlg], eax |
||
827 | push edi |
||
828 | call [DialogBox] |
||
829 | inc eax |
||
830 | jz .ret |
||
831 | ; convert ANSI-cp866 to UNICODE string; also calculate 'password_size' |
||
832 | mov esi, password_ansi |
||
833 | mov edi, password_unicode |
||
834 | or [password_size], -1 |
||
835 | .cvt: |
||
836 | inc [password_size] |
||
837 | lodsb |
||
838 | mov ah, 0 |
||
839 | ; 0x00-0x7F - trivial map |
||
840 | cmp al, 0x80 |
||
841 | jb .symb |
||
842 | ; 0x80-0xAF -> 0x410-0x43F |
||
843 | cmp al, 0xB0 |
||
844 | jae @f |
||
845 | add ax, 0x410-0x80 |
||
846 | jmp .symb |
||
847 | @@: |
||
848 | ; 0xE0-0xEF -> 0x440-0x44F |
||
849 | cmp al, 0xE0 |
||
850 | jb .unk |
||
851 | cmp al, 0xF0 |
||
852 | jae @f |
||
853 | add ax, 0x440-0xE0 |
||
854 | jmp .symb |
||
855 | @@: |
||
856 | ; 0xF0 -> 0x401 |
||
857 | ; 0xF1 -> 0x451 |
||
858 | cmp al, 'Ё' |
||
859 | jz .yo1 |
||
860 | cmp al, 'ё' |
||
861 | jz .yo2 |
||
862 | .unk: |
||
863 | mov al, '_' |
||
864 | jmp .symb |
||
865 | .yo1: |
||
866 | mov ax, 0x401 |
||
867 | jmp .symb |
||
868 | .yo2: |
||
869 | mov ax, 0x451 |
||
870 | .symb: |
||
871 | stosw |
||
872 | test al, al |
||
873 | jnz .cvt |
||
874 | inc [bPasswordDefined] ; clears ZF flag |
||
875 | .ret: |
||
876 | ret |
||
877 | |||
878 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
879 | ;;;;;;;;;;;;;;;; Initialized data ;;;;;;;;;;;;;;; |
||
880 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
881 | |||
882 | ; export table |
||
883 | align 4 |
||
884 | EXPORTS: |
||
885 | dd aVersion, 1 |
||
886 | dd aPluginLoad, plugin_load |
||
887 | dd aOpenFilePlugin,OpenFilePlugin |
||
888 | dd aClosePlugin, ClosePlugin |
||
889 | dd aReadFolder, ReadFolder |
||
890 | dd aSetFolder, SetFolder |
||
891 | dd aGetFiles, GetFiles |
||
892 | dd aGetOpenPluginInfo, GetOpenPluginInfo |
||
893 | dd aGetattr, mygetattr |
||
894 | dd aOpen, myopen |
||
895 | dd aRead, myread |
||
896 | dd aSetpos, mysetpos |
||
897 | dd aClose, myclose |
||
898 | dd 0 |
||
899 | |||
900 | ; exported names |
||
901 | aVersion db 'version',0 |
||
902 | aPluginLoad db 'plugin_load',0 |
||
903 | aOpenFilePlugin db 'OpenFilePlugin',0 |
||
904 | aClosePlugin db 'ClosePlugin',0 |
||
905 | aReadFolder db 'ReadFolder',0 |
||
906 | aSetFolder db 'SetFolder',0 |
||
907 | aGetFiles db 'GetFiles',0 |
||
908 | aGetOpenPluginInfo db 'GetOpenPluginInfo',0 |
||
909 | aGetattr db 'getattr',0 |
||
910 | aOpen db 'open',0 |
||
911 | aRead db 'read',0 |
||
912 | aSetpos db 'setpos',0 |
||
913 | aClose db 'close',0 |
||
914 | |||
915 | ; common strings |
||
916 | if lang eq ru |
||
917 | aContinue db 'Продолжить',0 |
||
918 | aCancel db 'Отмена',0 |
||
919 | aHeaderError db 'Ошибка в заголовке архива',0 |
||
920 | aReadError db 'Ошибка чтения',0 |
||
921 | aNoFreeRam db 'Недостаточно свободной оперативной памяти',0 |
||
922 | aEncodingProblem db 'Проблема с кодировкой',0 |
||
923 | aEncodingProblem_str db 'Имена некоторых файлов в архиве содержат символы,',0 |
||
924 | .2 db 'не представимые в кодировке cp866.',0 |
||
925 | .3 db 'Эти символы будут заменены на подчёркивания.',0 |
||
926 | aEnterPassword db 'Введите пароль:',0 |
||
927 | aEnterPasswordLen = $ - aEnterPassword - 1 |
||
928 | aEnterPasswordTitle db 'Ввод пароля',0 |
||
929 | aArchiveDataError db 'Ошибка в данных архива',0 |
||
930 | aArchiveDataErrorPass db 'Ошибка в данных архива или неверный пароль',0 |
||
931 | aChangePass db 'Ввести пароль',0 |
||
932 | aNameTooLong db 'Слишком длинное имя',0 |
||
933 | else |
||
934 | aContinue db 'Continue',0 |
||
935 | aCancel db 'Cancel',0 |
||
936 | aHeaderError db 'Invalid archive header',0 |
||
937 | aReadError db 'Read error',0 |
||
938 | aNoFreeRam db 'There is not enough of free RAM',0 |
||
939 | aEncodingProblem db 'Encoding problem',0 |
||
940 | aEncodingProblem_str db 'The names of some files in the archive contain',0 |
||
941 | .2 db 'characters which can not be represented in cp866.',0 |
||
942 | .3 db 'Such characters will be replaced to underscores.',0 |
||
943 | aEnterPassword db 'Enter password:',0 |
||
944 | aEnterPasswordLen = $ - aEnterPassword - 1 |
||
945 | aEnterPasswordTitle db 'Get password',0 |
||
946 | aArchiveDataError db 'Error in archive data',0 |
||
947 | aArchiveDataErrorPass db 'Error in archive data or incorrect password',0 |
||
948 | aChangePass db 'Enter password',0 |
||
949 | aNameTooLong db 'Name is too long',0 |
||
950 | end if |
||
951 | |||
952 | ; kfar_arc supports [hmm... will support...] many archive types. |
||
953 | ; OpenFilePlugin looks for supported archive signature and gives control |
||
954 | ; to concrete handler if found. |
||
955 | ; Other functions just determine type of opened archive and jumps to corresponding handler. |
||
956 | type_mem_stream = 0 ; memory stream - for file handles (returned from 'open') |
||
957 | type_7z = 1 |
||
958 | |||
959 | ; archive functions (types start from type_7z) |
||
960 | align 4 |
||
961 | ClosePluginTable: |
||
962 | dd close_7z |
||
963 | ReadFolderTable: |
||
964 | dd ReadFolder_7z |
||
965 | SetFolderTable: |
||
966 | dd SetFolder_7z |
||
967 | GetFilesTable: |
||
968 | dd GetFiles_7z |
||
969 | getattrTable: |
||
970 | dd getattr_7z |
||
971 | openTable: |
||
972 | dd open_file_7z |
||
973 | |||
974 | ; file functions (types start from type_mem_stream) |
||
975 | readTable: |
||
976 | dd read_mem_stream |
||
977 | dd read_7z |
||
978 | setposTable: |
||
979 | dd setpos_mem_stream |
||
980 | dd setpos_7z |
||
981 | closeTable: |
||
982 | dd close_mem_stream |
||
983 | dd close_file_7z |
||
984 | |||
985 | ; pointers for SayErr and Message |
||
986 | ContinueBtn dd aContinue |
||
987 | HeaderError_ptr dd aHeaderError |
||
988 | aReadError_ptr dd aReadError |
||
989 | aNoFreeRam_ptr dd aNoFreeRam |
||
990 | aEncodingProblem_str_ptr: |
||
991 | dd aEncodingProblem_str |
||
992 | dd aEncodingProblem_str.2 |
||
993 | dd aEncodingProblem_str.3 |
||
994 | aNameTooLong_ptr dd aNameTooLong |
||
995 | aArchiveDataError_ptr dd aArchiveDataError |
||
996 | aArchiveDataErrorPass_ptr dd aArchiveDataErrorPass |
||
997 | CancelPassBtn dd aCancel |
||
998 | dd aChangePass |
||
999 | |||
1000 | ; "enter password" dialog for KFar |
||
1001 | password_dlg: |
||
1002 | dd 1 ; use standard dialog colors |
||
1003 | dd -1 ; center window by x |
||
1004 | dd -1 ; center window by y |
||
1005 | .width dd ? ; width (will be filled according to current console width) |
||
1006 | dd 2 ; height |
||
1007 | dd 4, 2 ; border size |
||
1008 | dd aEnterPasswordTitle ; title |
||
1009 | dd ? ; colors (will be set by KFar) |
||
1010 | dd 0, 0 ; reserved for DlgProc |
||
1011 | dd 2 ; 2 controls |
||
1012 | ; the string "enter password" |
||
1013 | dd 1 ; type: static |
||
1014 | dd 1,0 ; upper-left position |
||
1015 | .width1 dd ?,0 ; bottom-right position |
||
1016 | dd aEnterPassword ; data |
||
1017 | dd 0 ; flags |
||
1018 | ; editbox for password |
||
1019 | dd 3 ; type: edit |
||
1020 | dd 1,1 ; upper-left position |
||
1021 | .width2 dd ?,0 ; bottom-right position |
||
1022 | dd password_data ; data |
||
1023 | dd 2Ch ; flags |
||
1024 | |||
1025 | IncludeIGlobals |
||
1026 | |||
1027 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
1028 | ;;;;;;;;;;;;;;; Uninitialized data ;;;;;;;;;;;;;; |
||
1029 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
1030 | |||
1031 | section '.udata' data readable writable align 16 |
||
1032 | kfar_info dd ? |
||
1033 | crc_table rd 256 |
||
1034 | _esp dd ? |
||
1035 | _ebp dd ? |
||
1036 | bufsize dd ? |
||
1037 | bufptr dd ? |
||
1038 | bufend dd ? |
||
1039 | buffer rb 1024 |
||
1040 | inStream dd ? |
||
1041 | hOut dd ? |
||
1042 | .allocated dd ? |
||
1043 | |||
1044 | error_proc dd ? |
||
1045 | clear_proc dd ? |
||
1046 | |||
1047 | ; import from kfar |
||
1048 | read dd ? |
||
1049 | seek dd ? |
||
1050 | close dd ? |
||
1051 | pgalloc dd ? |
||
1052 | pgrealloc dd ? |
||
1053 | pgfree dd ? |
||
1054 | getfreemem dd ? |
||
1055 | DialogBox dd ? |
||
1056 | SayErr dd ? |
||
1057 | Message dd ? |
||
1058 | cur_console_size dd ? |
||
1059 | |||
1060 | ; data for editbox in kfar dialog |
||
1061 | password_maxlen = 512 |
||
1062 | password_data: |
||
1063 | .maxlen dd ? |
||
1064 | .pos dd ? |
||
1065 | .start dd ? |
||
1066 | password_ansi rb password_maxlen+1 |
||
1067 | bPasswordDefined db ? |
||
1068 | |||
1069 | ; converted password |
||
1070 | password_unicode rw password_maxlen+1 |
||
1071 | password_size dd ? |
||
1072 | |||
1073 | IncludeUGlobals |
||
1074 | |||
1075 | bWasWarning db ?=>> |