; 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 .stamp dd ? .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 ? .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+12] 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.bufDataLen] 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_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] 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 @@: inc edx ; Deflate decoder: method ID = [size=03] 04 01 08, NumInStreams = NumOutStreams = 1 cmp dword [eax+4], 0x08010403 jnz @f cmp dword [eax+8], 1 jz .ret @@: inc edx ; Deflate64 decoder: method ID = [size=03] 04 01 09, NumInStreams = NumOutStreams = 1 cmp dword [eax+4], 0x09010403 jnz @f cmp dword [eax+8], 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 dd deflate_get_buf_size dd deflate_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 dd deflate_init_decoder dd deflate64_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 ; 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: push 0x10 ; attributes: folder pop eax stosd xor eax, eax stosd lea esi, [ebp+handle_7z.host_datetime] push 6 pop ecx rep movsd stosd stosd 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